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 | |
| 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.
| -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 | ||||
| -rw-r--r-- | src/ChangeLog | 30 | ||||
| -rw-r--r-- | src/alloc.c | 20 | ||||
| -rw-r--r-- | src/bytecode.c | 79 | ||||
| -rw-r--r-- | src/eval.c | 336 | ||||
| -rw-r--r-- | src/lisp.h | 111 |
9 files changed, 484 insertions, 315 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 | ||
diff --git a/src/ChangeLog b/src/ChangeLog index c201df19851..4b1bfc75187 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,5 +1,35 @@ | |||
| 1 | 2013-10-03 Stefan Monnier <monnier@iro.umontreal.ca> | 1 | 2013-10-03 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 2 | ||
| 3 | * lisp.h (struct handler): Merge struct handler and struct catchtag. | ||
| 4 | (PUSH_HANDLER): New macro. | ||
| 5 | (catchlist): Remove. | ||
| 6 | (handlerlist): Always declare. | ||
| 7 | |||
| 8 | * eval.c (catchlist): Remove (merge with handlerlist). | ||
| 9 | (handlerlist, lisp_eval_depth): Not static any more. | ||
| 10 | (internal_catch, internal_condition_case, internal_condition_case_1) | ||
| 11 | (internal_condition_case_2, internal_condition_case_n): | ||
| 12 | Use PUSH_HANDLER. | ||
| 13 | (unwind_to_catch, Fthrow, Fsignal): Adjust to merged | ||
| 14 | handlerlist/catchlist. | ||
| 15 | (internal_lisp_condition_case): Use PUSH_HANDLER. Adjust to new | ||
| 16 | handlerlist which can only handle a single condition-case handler at | ||
| 17 | a time. | ||
| 18 | (find_handler_clause): Simplify since we only a single branch here | ||
| 19 | any more. | ||
| 20 | |||
| 21 | * bytecode.c (BYTE_CODES): Add Bpushcatch, Bpushconditioncase | ||
| 22 | and Bpophandler. | ||
| 23 | (bcall0): New function. | ||
| 24 | (exec_byte_code): Add corresponding cases. Improve error message when | ||
| 25 | encountering an invalid byte-code. Let Bunwind_protect accept | ||
| 26 | a function (rather than a list of expressions) as argument. | ||
| 27 | |||
| 28 | * alloc.c (Fgarbage_collect): Merge scans of handlerlist and catchlist, | ||
| 29 | and make them unconditional now that they're heap-allocated. | ||
| 30 | |||
| 31 | 2013-10-03 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 32 | |||
| 3 | * charset.c (Fdecode_char, Fencode_char): Remove description of | 33 | * charset.c (Fdecode_char, Fencode_char): Remove description of |
| 4 | `restriction' arg. now that it's hidden by advertised-calling-convention. | 34 | `restriction' arg. now that it's hidden by advertised-calling-convention. |
| 5 | 35 | ||
diff --git a/src/alloc.c b/src/alloc.c index 2d9828ffa79..6b07f0bd7b1 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -5370,23 +5370,15 @@ See Info node `(elisp)Garbage Collection'. */) | |||
| 5370 | mark_object (tail->var[i]); | 5370 | mark_object (tail->var[i]); |
| 5371 | } | 5371 | } |
| 5372 | mark_byte_stack (); | 5372 | mark_byte_stack (); |
| 5373 | #endif | ||
| 5373 | { | 5374 | { |
| 5374 | struct catchtag *catch; | ||
| 5375 | struct handler *handler; | 5375 | struct handler *handler; |
| 5376 | 5376 | for (handler = handlerlist; handler; handler = handler->next) | |
| 5377 | for (catch = catchlist; catch; catch = catch->next) | 5377 | { |
| 5378 | { | 5378 | mark_object (handler->tag_or_ch); |
| 5379 | mark_object (catch->tag); | 5379 | mark_object (handler->val); |
| 5380 | mark_object (catch->val); | 5380 | } |
| 5381 | } | ||
| 5382 | for (handler = handlerlist; handler; handler = handler->next) | ||
| 5383 | { | ||
| 5384 | mark_object (handler->handler); | ||
| 5385 | mark_object (handler->var); | ||
| 5386 | } | ||
| 5387 | } | 5381 | } |
| 5388 | #endif | ||
| 5389 | |||
| 5390 | #ifdef HAVE_WINDOW_SYSTEM | 5382 | #ifdef HAVE_WINDOW_SYSTEM |
| 5391 | mark_fringe_data (); | 5383 | mark_fringe_data (); |
| 5392 | #endif | 5384 | #endif |
diff --git a/src/bytecode.c b/src/bytecode.c index 23e50826633..f7ccd35cbba 100644 --- a/src/bytecode.c +++ b/src/bytecode.c | |||
| @@ -141,6 +141,10 @@ DEFINE (Bunbind5, 055) \ | |||
| 141 | DEFINE (Bunbind6, 056) \ | 141 | DEFINE (Bunbind6, 056) \ |
| 142 | DEFINE (Bunbind7, 057) \ | 142 | DEFINE (Bunbind7, 057) \ |
| 143 | \ | 143 | \ |
| 144 | DEFINE (Bpophandler, 060) \ | ||
| 145 | DEFINE (Bpushconditioncase, 061) \ | ||
| 146 | DEFINE (Bpushcatch, 062) \ | ||
| 147 | \ | ||
| 144 | DEFINE (Bnth, 070) \ | 148 | DEFINE (Bnth, 070) \ |
| 145 | DEFINE (Bsymbolp, 071) \ | 149 | DEFINE (Bsymbolp, 071) \ |
| 146 | DEFINE (Bconsp, 072) \ | 150 | DEFINE (Bconsp, 072) \ |
| @@ -478,6 +482,12 @@ If the third argument is incorrect, Emacs may crash. */) | |||
| 478 | return exec_byte_code (bytestr, vector, maxdepth, Qnil, 0, NULL); | 482 | return exec_byte_code (bytestr, vector, maxdepth, Qnil, 0, NULL); |
| 479 | } | 483 | } |
| 480 | 484 | ||
| 485 | static void | ||
| 486 | bcall0 (Lisp_Object f) | ||
| 487 | { | ||
| 488 | Ffuncall (1, &f); | ||
| 489 | } | ||
| 490 | |||
| 481 | /* Execute the byte-code in BYTESTR. VECTOR is the constant vector, and | 491 | /* Execute the byte-code in BYTESTR. VECTOR is the constant vector, and |
| 482 | MAXDEPTH is the maximum stack depth used (if MAXDEPTH is incorrect, | 492 | MAXDEPTH is the maximum stack depth used (if MAXDEPTH is incorrect, |
| 483 | emacs may crash!). If ARGS_TEMPLATE is non-nil, it should be a lisp | 493 | emacs may crash!). If ARGS_TEMPLATE is non-nil, it should be a lisp |
| @@ -506,6 +516,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 506 | struct byte_stack stack; | 516 | struct byte_stack stack; |
| 507 | Lisp_Object *top; | 517 | Lisp_Object *top; |
| 508 | Lisp_Object result; | 518 | Lisp_Object result; |
| 519 | enum handlertype type; | ||
| 509 | 520 | ||
| 510 | #if 0 /* CHECK_FRAME_FONT */ | 521 | #if 0 /* CHECK_FRAME_FONT */ |
| 511 | { | 522 | { |
| @@ -1078,7 +1089,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 1078 | save_restriction_save ()); | 1089 | save_restriction_save ()); |
| 1079 | NEXT; | 1090 | NEXT; |
| 1080 | 1091 | ||
| 1081 | CASE (Bcatch): /* FIXME: ill-suited for lexbind. */ | 1092 | CASE (Bcatch): /* Obsolete since 24.4. */ |
| 1082 | { | 1093 | { |
| 1083 | Lisp_Object v1; | 1094 | Lisp_Object v1; |
| 1084 | BEFORE_POTENTIAL_GC (); | 1095 | BEFORE_POTENTIAL_GC (); |
| @@ -1088,11 +1099,56 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 1088 | NEXT; | 1099 | NEXT; |
| 1089 | } | 1100 | } |
| 1090 | 1101 | ||
| 1102 | CASE (Bpushcatch): /* New in 24.4. */ | ||
| 1103 | type = CATCHER; | ||
| 1104 | goto pushhandler; | ||
| 1105 | CASE (Bpushconditioncase): /* New in 24.4. */ | ||
| 1106 | { | ||
| 1107 | extern EMACS_INT lisp_eval_depth; | ||
| 1108 | extern int poll_suppress_count; | ||
| 1109 | extern int interrupt_input_blocked; | ||
| 1110 | struct handler *c; | ||
| 1111 | Lisp_Object tag; | ||
| 1112 | int dest; | ||
| 1113 | |||
| 1114 | type = CONDITION_CASE; | ||
| 1115 | pushhandler: | ||
| 1116 | tag = POP; | ||
| 1117 | dest = FETCH2; | ||
| 1118 | |||
| 1119 | PUSH_HANDLER (c, tag, type); | ||
| 1120 | c->bytecode_dest = dest; | ||
| 1121 | c->bytecode_top = top; | ||
| 1122 | if (sys_setjmp (c->jmp)) | ||
| 1123 | { | ||
| 1124 | struct handler *c = handlerlist; | ||
| 1125 | top = c->bytecode_top; | ||
| 1126 | int dest = c->bytecode_dest; | ||
| 1127 | handlerlist = c->next; | ||
| 1128 | PUSH (c->val); | ||
| 1129 | CHECK_RANGE (dest); | ||
| 1130 | stack.pc = stack.byte_string_start + dest; | ||
| 1131 | } | ||
| 1132 | NEXT; | ||
| 1133 | } | ||
| 1134 | |||
| 1135 | CASE (Bpophandler): /* New in 24.4. */ | ||
| 1136 | { | ||
| 1137 | handlerlist = handlerlist->next; | ||
| 1138 | NEXT; | ||
| 1139 | } | ||
| 1140 | |||
| 1091 | CASE (Bunwind_protect): /* FIXME: avoid closure for lexbind. */ | 1141 | CASE (Bunwind_protect): /* FIXME: avoid closure for lexbind. */ |
| 1092 | record_unwind_protect (unwind_body, POP); | 1142 | { |
| 1093 | NEXT; | 1143 | Lisp_Object handler = POP; |
| 1144 | /* Support for a function here is new in 24.4. */ | ||
| 1145 | record_unwind_protect (NILP (Ffunctionp (handler)) | ||
| 1146 | ? unwind_body : bcall0, | ||
| 1147 | handler); | ||
| 1148 | NEXT; | ||
| 1149 | } | ||
| 1094 | 1150 | ||
| 1095 | CASE (Bcondition_case): /* FIXME: ill-suited for lexbind. */ | 1151 | CASE (Bcondition_case): /* Obsolete since 24.4. */ |
| 1096 | { | 1152 | { |
| 1097 | Lisp_Object handlers, body; | 1153 | Lisp_Object handlers, body; |
| 1098 | handlers = POP; | 1154 | handlers = POP; |
| @@ -1884,7 +1940,10 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 1884 | /* Actually this is Bstack_ref with offset 0, but we use Bdup | 1940 | /* Actually this is Bstack_ref with offset 0, but we use Bdup |
| 1885 | for that instead. */ | 1941 | for that instead. */ |
| 1886 | /* CASE (Bstack_ref): */ | 1942 | /* CASE (Bstack_ref): */ |
| 1887 | error ("Invalid byte opcode"); | 1943 | call3 (intern ("error"), |
| 1944 | build_string ("Invalid byte opcode: op=%s, ptr=%d"), | ||
| 1945 | make_number (op), | ||
| 1946 | make_number ((stack.pc - 1) - stack.byte_string_start)); | ||
| 1888 | 1947 | ||
| 1889 | /* Handy byte-codes for lexical binding. */ | 1948 | /* Handy byte-codes for lexical binding. */ |
| 1890 | CASE (Bstack_ref1): | 1949 | CASE (Bstack_ref1): |
| @@ -1957,11 +2016,11 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 1957 | 2016 | ||
| 1958 | /* Binds and unbinds are supposed to be compiled balanced. */ | 2017 | /* Binds and unbinds are supposed to be compiled balanced. */ |
| 1959 | if (SPECPDL_INDEX () != count) | 2018 | if (SPECPDL_INDEX () != count) |
| 1960 | #ifdef BYTE_CODE_SAFE | 2019 | { |
| 1961 | error ("binding stack not balanced (serious byte compiler bug)"); | 2020 | if (SPECPDL_INDEX () > count) |
| 1962 | #else | 2021 | unbind_to (count, Qnil); |
| 1963 | emacs_abort (); | 2022 | error ("binding stack not balanced (serious byte compiler bug)"); |
| 1964 | #endif | 2023 | } |
| 1965 | 2024 | ||
| 1966 | return result; | 2025 | return result; |
| 1967 | } | 2026 | } |
diff --git a/src/eval.c b/src/eval.c index 6e964f6604b..5526b28b2e0 100644 --- a/src/eval.c +++ b/src/eval.c | |||
| @@ -32,20 +32,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 32 | #include "xterm.h" | 32 | #include "xterm.h" |
| 33 | #endif | 33 | #endif |
| 34 | 34 | ||
| 35 | #if !BYTE_MARK_STACK | 35 | /* Chain of condition and catch handlers currently in effect. */ |
| 36 | static | ||
| 37 | #endif | ||
| 38 | struct catchtag *catchlist; | ||
| 39 | |||
| 40 | /* Chain of condition handlers currently in effect. | ||
| 41 | The elements of this chain are contained in the stack frames | ||
| 42 | of Fcondition_case and internal_condition_case. | ||
| 43 | When an error is signaled (by calling Fsignal, below), | ||
| 44 | this chain is searched for an element that applies. */ | ||
| 45 | 36 | ||
| 46 | #if !BYTE_MARK_STACK | ||
| 47 | static | ||
| 48 | #endif | ||
| 49 | struct handler *handlerlist; | 37 | struct handler *handlerlist; |
| 50 | 38 | ||
| 51 | #ifdef DEBUG_GCPRO | 39 | #ifdef DEBUG_GCPRO |
| @@ -92,7 +80,7 @@ union specbinding *specpdl_ptr; | |||
| 92 | 80 | ||
| 93 | /* Depth in Lisp evaluations and function calls. */ | 81 | /* Depth in Lisp evaluations and function calls. */ |
| 94 | 82 | ||
| 95 | static EMACS_INT lisp_eval_depth; | 83 | EMACS_INT lisp_eval_depth; |
| 96 | 84 | ||
| 97 | /* The value of num_nonmacro_input_events as of the last time we | 85 | /* The value of num_nonmacro_input_events as of the last time we |
| 98 | started to enter the debugger. If we decide to enter the debugger | 86 | started to enter the debugger. If we decide to enter the debugger |
| @@ -253,8 +241,7 @@ void | |||
| 253 | init_eval (void) | 241 | init_eval (void) |
| 254 | { | 242 | { |
| 255 | specpdl_ptr = specpdl; | 243 | specpdl_ptr = specpdl; |
| 256 | catchlist = 0; | 244 | handlerlist = NULL; |
| 257 | handlerlist = 0; | ||
| 258 | Vquit_flag = Qnil; | 245 | Vquit_flag = Qnil; |
| 259 | debug_on_next_call = 0; | 246 | debug_on_next_call = 0; |
| 260 | lisp_eval_depth = 0; | 247 | lisp_eval_depth = 0; |
| @@ -1093,28 +1080,26 @@ Lisp_Object | |||
| 1093 | internal_catch (Lisp_Object tag, Lisp_Object (*func) (Lisp_Object), Lisp_Object arg) | 1080 | internal_catch (Lisp_Object tag, Lisp_Object (*func) (Lisp_Object), Lisp_Object arg) |
| 1094 | { | 1081 | { |
| 1095 | /* This structure is made part of the chain `catchlist'. */ | 1082 | /* This structure is made part of the chain `catchlist'. */ |
| 1096 | struct catchtag c; | 1083 | struct handler *c; |
| 1097 | 1084 | ||
| 1098 | /* Fill in the components of c, and put it on the list. */ | 1085 | /* Fill in the components of c, and put it on the list. */ |
| 1099 | c.next = catchlist; | 1086 | PUSH_HANDLER (c, tag, CATCHER); |
| 1100 | c.tag = tag; | ||
| 1101 | c.val = Qnil; | ||
| 1102 | c.handlerlist = handlerlist; | ||
| 1103 | c.lisp_eval_depth = lisp_eval_depth; | ||
| 1104 | c.pdlcount = SPECPDL_INDEX (); | ||
| 1105 | c.poll_suppress_count = poll_suppress_count; | ||
| 1106 | c.interrupt_input_blocked = interrupt_input_blocked; | ||
| 1107 | c.gcpro = gcprolist; | ||
| 1108 | c.byte_stack = byte_stack_list; | ||
| 1109 | catchlist = &c; | ||
| 1110 | 1087 | ||
| 1111 | /* Call FUNC. */ | 1088 | /* Call FUNC. */ |
| 1112 | if (! sys_setjmp (c.jmp)) | 1089 | if (! sys_setjmp (c->jmp)) |
| 1113 | c.val = (*func) (arg); | 1090 | { |
| 1114 | 1091 | Lisp_Object val = (*func) (arg); | |
| 1115 | /* Throw works by a longjmp that comes right here. */ | 1092 | eassert (handlerlist == c); |
| 1116 | catchlist = c.next; | 1093 | handlerlist = c->next; |
| 1117 | return c.val; | 1094 | return val; |
| 1095 | } | ||
| 1096 | else | ||
| 1097 | { /* Throw works by a longjmp that comes right here. */ | ||
| 1098 | Lisp_Object val = handlerlist->val; | ||
| 1099 | eassert (handlerlist == c); | ||
| 1100 | handlerlist = handlerlist->next; | ||
| 1101 | return val; | ||
| 1102 | } | ||
| 1118 | } | 1103 | } |
| 1119 | 1104 | ||
| 1120 | /* Unwind the specbind, catch, and handler stacks back to CATCH, and | 1105 | /* Unwind the specbind, catch, and handler stacks back to CATCH, and |
| @@ -1134,7 +1119,7 @@ internal_catch (Lisp_Object tag, Lisp_Object (*func) (Lisp_Object), Lisp_Object | |||
| 1134 | This is used for correct unwinding in Fthrow and Fsignal. */ | 1119 | This is used for correct unwinding in Fthrow and Fsignal. */ |
| 1135 | 1120 | ||
| 1136 | static _Noreturn void | 1121 | static _Noreturn void |
| 1137 | unwind_to_catch (struct catchtag *catch, Lisp_Object value) | 1122 | unwind_to_catch (struct handler *catch, Lisp_Object value) |
| 1138 | { | 1123 | { |
| 1139 | bool last_time; | 1124 | bool last_time; |
| 1140 | 1125 | ||
| @@ -1148,16 +1133,17 @@ unwind_to_catch (struct catchtag *catch, Lisp_Object value) | |||
| 1148 | 1133 | ||
| 1149 | do | 1134 | do |
| 1150 | { | 1135 | { |
| 1151 | last_time = catchlist == catch; | ||
| 1152 | |||
| 1153 | /* Unwind the specpdl stack, and then restore the proper set of | 1136 | /* Unwind the specpdl stack, and then restore the proper set of |
| 1154 | handlers. */ | 1137 | handlers. */ |
| 1155 | unbind_to (catchlist->pdlcount, Qnil); | 1138 | unbind_to (handlerlist->pdlcount, Qnil); |
| 1156 | handlerlist = catchlist->handlerlist; | 1139 | last_time = handlerlist == catch; |
| 1157 | catchlist = catchlist->next; | 1140 | if (! last_time) |
| 1141 | handlerlist = handlerlist->next; | ||
| 1158 | } | 1142 | } |
| 1159 | while (! last_time); | 1143 | while (! last_time); |
| 1160 | 1144 | ||
| 1145 | eassert (handlerlist == catch); | ||
| 1146 | |||
| 1161 | byte_stack_list = catch->byte_stack; | 1147 | byte_stack_list = catch->byte_stack; |
| 1162 | gcprolist = catch->gcpro; | 1148 | gcprolist = catch->gcpro; |
| 1163 | #ifdef DEBUG_GCPRO | 1149 | #ifdef DEBUG_GCPRO |
| @@ -1173,12 +1159,12 @@ DEFUN ("throw", Fthrow, Sthrow, 2, 2, 0, | |||
| 1173 | Both TAG and VALUE are evalled. */) | 1159 | Both TAG and VALUE are evalled. */) |
| 1174 | (register Lisp_Object tag, Lisp_Object value) | 1160 | (register Lisp_Object tag, Lisp_Object value) |
| 1175 | { | 1161 | { |
| 1176 | register struct catchtag *c; | 1162 | struct handler *c; |
| 1177 | 1163 | ||
| 1178 | if (!NILP (tag)) | 1164 | if (!NILP (tag)) |
| 1179 | for (c = catchlist; c; c = c->next) | 1165 | for (c = handlerlist; c; c = c->next) |
| 1180 | { | 1166 | { |
| 1181 | if (EQ (c->tag, tag)) | 1167 | if (c->type == CATCHER && EQ (c->tag_or_ch, tag)) |
| 1182 | unwind_to_catch (c, value); | 1168 | unwind_to_catch (c, value); |
| 1183 | } | 1169 | } |
| 1184 | xsignal2 (Qno_catch, tag, value); | 1170 | xsignal2 (Qno_catch, tag, value); |
| @@ -1244,15 +1230,16 @@ internal_lisp_condition_case (volatile Lisp_Object var, Lisp_Object bodyform, | |||
| 1244 | Lisp_Object handlers) | 1230 | Lisp_Object handlers) |
| 1245 | { | 1231 | { |
| 1246 | Lisp_Object val; | 1232 | Lisp_Object val; |
| 1247 | struct catchtag c; | 1233 | struct handler *c; |
| 1248 | struct handler h; | 1234 | struct handler *oldhandlerlist = handlerlist; |
| 1235 | int clausenb = 0; | ||
| 1249 | 1236 | ||
| 1250 | CHECK_SYMBOL (var); | 1237 | CHECK_SYMBOL (var); |
| 1251 | 1238 | ||
| 1252 | for (val = handlers; CONSP (val); val = XCDR (val)) | 1239 | for (val = handlers; CONSP (val); val = XCDR (val)) |
| 1253 | { | 1240 | { |
| 1254 | Lisp_Object tem; | 1241 | Lisp_Object tem = XCAR (val); |
| 1255 | tem = XCAR (val); | 1242 | clausenb++; |
| 1256 | if (! (NILP (tem) | 1243 | if (! (NILP (tem) |
| 1257 | || (CONSP (tem) | 1244 | || (CONSP (tem) |
| 1258 | && (SYMBOLP (XCAR (tem)) | 1245 | && (SYMBOLP (XCAR (tem)) |
| @@ -1261,39 +1248,50 @@ internal_lisp_condition_case (volatile Lisp_Object var, Lisp_Object bodyform, | |||
| 1261 | SDATA (Fprin1_to_string (tem, Qt))); | 1248 | SDATA (Fprin1_to_string (tem, Qt))); |
| 1262 | } | 1249 | } |
| 1263 | 1250 | ||
| 1264 | c.tag = Qnil; | 1251 | { /* The first clause is the one that should be checked first, so it should |
| 1265 | c.val = Qnil; | 1252 | be added to handlerlist last. So we build in `clauses' a table that |
| 1266 | c.handlerlist = handlerlist; | 1253 | contains `handlers' but in reverse order. */ |
| 1267 | c.lisp_eval_depth = lisp_eval_depth; | 1254 | Lisp_Object *clauses = alloca (clausenb * sizeof (Lisp_Object *)); |
| 1268 | c.pdlcount = SPECPDL_INDEX (); | 1255 | int i = clausenb; |
| 1269 | c.poll_suppress_count = poll_suppress_count; | 1256 | for (val = handlers; CONSP (val); val = XCDR (val)) |
| 1270 | c.interrupt_input_blocked = interrupt_input_blocked; | 1257 | clauses[--i] = XCAR (val); |
| 1271 | c.gcpro = gcprolist; | 1258 | for (i = 0; i < clausenb; i++) |
| 1272 | c.byte_stack = byte_stack_list; | 1259 | { |
| 1273 | if (sys_setjmp (c.jmp)) | 1260 | Lisp_Object clause = clauses[i]; |
| 1274 | { | 1261 | Lisp_Object condition = XCAR (clause); |
| 1275 | if (!NILP (h.var)) | 1262 | if (!CONSP (condition)) |
| 1276 | specbind (h.var, c.val); | 1263 | condition = Fcons (condition, Qnil); |
| 1277 | val = Fprogn (Fcdr (h.chosen_clause)); | 1264 | PUSH_HANDLER (c, condition, CONDITION_CASE); |
| 1278 | 1265 | if (sys_setjmp (c->jmp)) | |
| 1279 | /* Note that this just undoes the binding of h.var; whoever | 1266 | { |
| 1280 | longjumped to us unwound the stack to c.pdlcount before | 1267 | ptrdiff_t count = SPECPDL_INDEX (); |
| 1281 | throwing. */ | 1268 | Lisp_Object val = handlerlist->val; |
| 1282 | unbind_to (c.pdlcount, Qnil); | 1269 | Lisp_Object *chosen_clause = clauses; |
| 1283 | return val; | 1270 | for (c = handlerlist->next; c != oldhandlerlist; c = c->next) |
| 1271 | chosen_clause++; | ||
| 1272 | handlerlist = oldhandlerlist; | ||
| 1273 | if (!NILP (var)) | ||
| 1274 | { | ||
| 1275 | if (!NILP (Vinternal_interpreter_environment)) | ||
| 1276 | specbind (Qinternal_interpreter_environment, | ||
| 1277 | Fcons (Fcons (var, val), | ||
| 1278 | Vinternal_interpreter_environment)); | ||
| 1279 | else | ||
| 1280 | specbind (var, val); | ||
| 1281 | } | ||
| 1282 | val = Fprogn (XCDR (*chosen_clause)); | ||
| 1283 | /* Note that this just undoes the binding of var; whoever | ||
| 1284 | longjumped to us unwound the stack to c.pdlcount before | ||
| 1285 | throwing. */ | ||
| 1286 | if (!NILP (var)) | ||
| 1287 | unbind_to (count, Qnil); | ||
| 1288 | return val; | ||
| 1289 | } | ||
| 1290 | } | ||
| 1284 | } | 1291 | } |
| 1285 | c.next = catchlist; | ||
| 1286 | catchlist = &c; | ||
| 1287 | |||
| 1288 | h.var = var; | ||
| 1289 | h.handler = handlers; | ||
| 1290 | h.next = handlerlist; | ||
| 1291 | h.tag = &c; | ||
| 1292 | handlerlist = &h; | ||
| 1293 | 1292 | ||
| 1294 | val = eval_sub (bodyform); | 1293 | val = eval_sub (bodyform); |
| 1295 | catchlist = c.next; | 1294 | handlerlist = oldhandlerlist; |
| 1296 | handlerlist = h.next; | ||
| 1297 | return val; | 1295 | return val; |
| 1298 | } | 1296 | } |
| 1299 | 1297 | ||
| @@ -1312,33 +1310,20 @@ internal_condition_case (Lisp_Object (*bfun) (void), Lisp_Object handlers, | |||
| 1312 | Lisp_Object (*hfun) (Lisp_Object)) | 1310 | Lisp_Object (*hfun) (Lisp_Object)) |
| 1313 | { | 1311 | { |
| 1314 | Lisp_Object val; | 1312 | Lisp_Object val; |
| 1315 | struct catchtag c; | 1313 | struct handler *c; |
| 1316 | struct handler h; | 1314 | |
| 1317 | 1315 | PUSH_HANDLER (c, handlers, CONDITION_CASE); | |
| 1318 | c.tag = Qnil; | 1316 | if (sys_setjmp (c->jmp)) |
| 1319 | c.val = Qnil; | 1317 | { |
| 1320 | c.handlerlist = handlerlist; | 1318 | Lisp_Object val = handlerlist->val; |
| 1321 | c.lisp_eval_depth = lisp_eval_depth; | 1319 | eassert (handlerlist == c); |
| 1322 | c.pdlcount = SPECPDL_INDEX (); | 1320 | handlerlist = handlerlist->next; |
| 1323 | c.poll_suppress_count = poll_suppress_count; | 1321 | return (*hfun) (val); |
| 1324 | c.interrupt_input_blocked = interrupt_input_blocked; | 1322 | } |
| 1325 | c.gcpro = gcprolist; | ||
| 1326 | c.byte_stack = byte_stack_list; | ||
| 1327 | if (sys_setjmp (c.jmp)) | ||
| 1328 | { | ||
| 1329 | return (*hfun) (c.val); | ||
| 1330 | } | ||
| 1331 | c.next = catchlist; | ||
| 1332 | catchlist = &c; | ||
| 1333 | h.handler = handlers; | ||
| 1334 | h.var = Qnil; | ||
| 1335 | h.next = handlerlist; | ||
| 1336 | h.tag = &c; | ||
| 1337 | handlerlist = &h; | ||
| 1338 | 1323 | ||
| 1339 | val = (*bfun) (); | 1324 | val = (*bfun) (); |
| 1340 | catchlist = c.next; | 1325 | eassert (handlerlist == c); |
| 1341 | handlerlist = h.next; | 1326 | handlerlist = c->next; |
| 1342 | return val; | 1327 | return val; |
| 1343 | } | 1328 | } |
| 1344 | 1329 | ||
| @@ -1349,33 +1334,20 @@ internal_condition_case_1 (Lisp_Object (*bfun) (Lisp_Object), Lisp_Object arg, | |||
| 1349 | Lisp_Object handlers, Lisp_Object (*hfun) (Lisp_Object)) | 1334 | Lisp_Object handlers, Lisp_Object (*hfun) (Lisp_Object)) |
| 1350 | { | 1335 | { |
| 1351 | Lisp_Object val; | 1336 | Lisp_Object val; |
| 1352 | struct catchtag c; | 1337 | struct handler *c; |
| 1353 | struct handler h; | 1338 | |
| 1354 | 1339 | PUSH_HANDLER (c, handlers, CONDITION_CASE); | |
| 1355 | c.tag = Qnil; | 1340 | if (sys_setjmp (c->jmp)) |
| 1356 | c.val = Qnil; | 1341 | { |
| 1357 | c.handlerlist = handlerlist; | 1342 | Lisp_Object val = handlerlist->val; |
| 1358 | c.lisp_eval_depth = lisp_eval_depth; | 1343 | eassert (handlerlist == c); |
| 1359 | c.pdlcount = SPECPDL_INDEX (); | 1344 | handlerlist = handlerlist->next; |
| 1360 | c.poll_suppress_count = poll_suppress_count; | 1345 | return (*hfun) (val); |
| 1361 | c.interrupt_input_blocked = interrupt_input_blocked; | 1346 | } |
| 1362 | c.gcpro = gcprolist; | ||
| 1363 | c.byte_stack = byte_stack_list; | ||
| 1364 | if (sys_setjmp (c.jmp)) | ||
| 1365 | { | ||
| 1366 | return (*hfun) (c.val); | ||
| 1367 | } | ||
| 1368 | c.next = catchlist; | ||
| 1369 | catchlist = &c; | ||
| 1370 | h.handler = handlers; | ||
| 1371 | h.var = Qnil; | ||
| 1372 | h.next = handlerlist; | ||
| 1373 | h.tag = &c; | ||
| 1374 | handlerlist = &h; | ||
| 1375 | 1347 | ||
| 1376 | val = (*bfun) (arg); | 1348 | val = (*bfun) (arg); |
| 1377 | catchlist = c.next; | 1349 | eassert (handlerlist == c); |
| 1378 | handlerlist = h.next; | 1350 | handlerlist = c->next; |
| 1379 | return val; | 1351 | return val; |
| 1380 | } | 1352 | } |
| 1381 | 1353 | ||
| @@ -1390,33 +1362,20 @@ internal_condition_case_2 (Lisp_Object (*bfun) (Lisp_Object, Lisp_Object), | |||
| 1390 | Lisp_Object (*hfun) (Lisp_Object)) | 1362 | Lisp_Object (*hfun) (Lisp_Object)) |
| 1391 | { | 1363 | { |
| 1392 | Lisp_Object val; | 1364 | Lisp_Object val; |
| 1393 | struct catchtag c; | 1365 | struct handler *c; |
| 1394 | struct handler h; | 1366 | |
| 1395 | 1367 | PUSH_HANDLER (c, handlers, CONDITION_CASE); | |
| 1396 | c.tag = Qnil; | 1368 | if (sys_setjmp (c->jmp)) |
| 1397 | c.val = Qnil; | 1369 | { |
| 1398 | c.handlerlist = handlerlist; | 1370 | Lisp_Object val = handlerlist->val; |
| 1399 | c.lisp_eval_depth = lisp_eval_depth; | 1371 | eassert (handlerlist == c); |
| 1400 | c.pdlcount = SPECPDL_INDEX (); | 1372 | handlerlist = handlerlist->next; |
| 1401 | c.poll_suppress_count = poll_suppress_count; | 1373 | return (*hfun) (val); |
| 1402 | c.interrupt_input_blocked = interrupt_input_blocked; | 1374 | } |
| 1403 | c.gcpro = gcprolist; | ||
| 1404 | c.byte_stack = byte_stack_list; | ||
| 1405 | if (sys_setjmp (c.jmp)) | ||
| 1406 | { | ||
| 1407 | return (*hfun) (c.val); | ||
| 1408 | } | ||
| 1409 | c.next = catchlist; | ||
| 1410 | catchlist = &c; | ||
| 1411 | h.handler = handlers; | ||
| 1412 | h.var = Qnil; | ||
| 1413 | h.next = handlerlist; | ||
| 1414 | h.tag = &c; | ||
| 1415 | handlerlist = &h; | ||
| 1416 | 1375 | ||
| 1417 | val = (*bfun) (arg1, arg2); | 1376 | val = (*bfun) (arg1, arg2); |
| 1418 | catchlist = c.next; | 1377 | eassert (handlerlist == c); |
| 1419 | handlerlist = h.next; | 1378 | handlerlist = c->next; |
| 1420 | return val; | 1379 | return val; |
| 1421 | } | 1380 | } |
| 1422 | 1381 | ||
| @@ -1433,33 +1392,20 @@ internal_condition_case_n (Lisp_Object (*bfun) (ptrdiff_t, Lisp_Object *), | |||
| 1433 | Lisp_Object *args)) | 1392 | Lisp_Object *args)) |
| 1434 | { | 1393 | { |
| 1435 | Lisp_Object val; | 1394 | Lisp_Object val; |
| 1436 | struct catchtag c; | 1395 | struct handler *c; |
| 1437 | struct handler h; | 1396 | |
| 1438 | 1397 | PUSH_HANDLER (c, handlers, CONDITION_CASE); | |
| 1439 | c.tag = Qnil; | 1398 | if (sys_setjmp (c->jmp)) |
| 1440 | c.val = Qnil; | 1399 | { |
| 1441 | c.handlerlist = handlerlist; | 1400 | Lisp_Object val = handlerlist->val; |
| 1442 | c.lisp_eval_depth = lisp_eval_depth; | 1401 | eassert (handlerlist == c); |
| 1443 | c.pdlcount = SPECPDL_INDEX (); | 1402 | handlerlist = handlerlist->next; |
| 1444 | c.poll_suppress_count = poll_suppress_count; | 1403 | return (*hfun) (val, nargs, args); |
| 1445 | c.interrupt_input_blocked = interrupt_input_blocked; | 1404 | } |
| 1446 | c.gcpro = gcprolist; | ||
| 1447 | c.byte_stack = byte_stack_list; | ||
| 1448 | if (sys_setjmp (c.jmp)) | ||
| 1449 | { | ||
| 1450 | return (*hfun) (c.val, nargs, args); | ||
| 1451 | } | ||
| 1452 | c.next = catchlist; | ||
| 1453 | catchlist = &c; | ||
| 1454 | h.handler = handlers; | ||
| 1455 | h.var = Qnil; | ||
| 1456 | h.next = handlerlist; | ||
| 1457 | h.tag = &c; | ||
| 1458 | handlerlist = &h; | ||
| 1459 | 1405 | ||
| 1460 | val = (*bfun) (nargs, args); | 1406 | val = (*bfun) (nargs, args); |
| 1461 | catchlist = c.next; | 1407 | eassert (handlerlist == c); |
| 1462 | handlerlist = h.next; | 1408 | handlerlist = c->next; |
| 1463 | return val; | 1409 | return val; |
| 1464 | } | 1410 | } |
| 1465 | 1411 | ||
| @@ -1551,7 +1497,9 @@ See also the function `condition-case'. */) | |||
| 1551 | 1497 | ||
| 1552 | for (h = handlerlist; h; h = h->next) | 1498 | for (h = handlerlist; h; h = h->next) |
| 1553 | { | 1499 | { |
| 1554 | clause = find_handler_clause (h->handler, conditions); | 1500 | if (h->type != CONDITION_CASE) |
| 1501 | continue; | ||
| 1502 | clause = find_handler_clause (h->tag_or_ch, conditions); | ||
| 1555 | if (!NILP (clause)) | 1503 | if (!NILP (clause)) |
| 1556 | break; | 1504 | break; |
| 1557 | } | 1505 | } |
| @@ -1568,7 +1516,7 @@ See also the function `condition-case'. */) | |||
| 1568 | && !NILP (Fmemq (Qdebug, XCAR (clause)))) | 1516 | && !NILP (Fmemq (Qdebug, XCAR (clause)))) |
| 1569 | /* Special handler that means "print a message and run debugger | 1517 | /* Special handler that means "print a message and run debugger |
| 1570 | if requested". */ | 1518 | if requested". */ |
| 1571 | || EQ (h->handler, Qerror))) | 1519 | || EQ (h->tag_or_ch, Qerror))) |
| 1572 | { | 1520 | { |
| 1573 | bool debugger_called | 1521 | bool debugger_called |
| 1574 | = maybe_call_debugger (conditions, error_symbol, data); | 1522 | = maybe_call_debugger (conditions, error_symbol, data); |
| @@ -1583,12 +1531,11 @@ See also the function `condition-case'. */) | |||
| 1583 | Lisp_Object unwind_data | 1531 | Lisp_Object unwind_data |
| 1584 | = (NILP (error_symbol) ? data : Fcons (error_symbol, data)); | 1532 | = (NILP (error_symbol) ? data : Fcons (error_symbol, data)); |
| 1585 | 1533 | ||
| 1586 | h->chosen_clause = clause; | 1534 | unwind_to_catch (h, unwind_data); |
| 1587 | unwind_to_catch (h->tag, unwind_data); | ||
| 1588 | } | 1535 | } |
| 1589 | else | 1536 | else |
| 1590 | { | 1537 | { |
| 1591 | if (catchlist != 0) | 1538 | if (handlerlist != 0) |
| 1592 | Fthrow (Qtop_level, Qt); | 1539 | Fthrow (Qtop_level, Qt); |
| 1593 | } | 1540 | } |
| 1594 | 1541 | ||
| @@ -1774,29 +1721,8 @@ find_handler_clause (Lisp_Object handlers, Lisp_Object conditions) | |||
| 1774 | for (h = handlers; CONSP (h); h = XCDR (h)) | 1721 | for (h = handlers; CONSP (h); h = XCDR (h)) |
| 1775 | { | 1722 | { |
| 1776 | Lisp_Object handler = XCAR (h); | 1723 | Lisp_Object handler = XCAR (h); |
| 1777 | Lisp_Object condit, tem; | 1724 | if (!NILP (Fmemq (handler, conditions))) |
| 1778 | 1725 | return handlers; | |
| 1779 | if (!CONSP (handler)) | ||
| 1780 | continue; | ||
| 1781 | condit = XCAR (handler); | ||
| 1782 | /* Handle a single condition name in handler HANDLER. */ | ||
| 1783 | if (SYMBOLP (condit)) | ||
| 1784 | { | ||
| 1785 | tem = Fmemq (Fcar (handler), conditions); | ||
| 1786 | if (!NILP (tem)) | ||
| 1787 | return handler; | ||
| 1788 | } | ||
| 1789 | /* Handle a list of condition names in handler HANDLER. */ | ||
| 1790 | else if (CONSP (condit)) | ||
| 1791 | { | ||
| 1792 | Lisp_Object tail; | ||
| 1793 | for (tail = condit; CONSP (tail); tail = XCDR (tail)) | ||
| 1794 | { | ||
| 1795 | tem = Fmemq (XCAR (tail), conditions); | ||
| 1796 | if (!NILP (tem)) | ||
| 1797 | return handler; | ||
| 1798 | } | ||
| 1799 | } | ||
| 1800 | } | 1726 | } |
| 1801 | 1727 | ||
| 1802 | return Qnil; | 1728 | return Qnil; |
diff --git a/src/lisp.h b/src/lisp.h index 63597e86be6..688c89c1eee 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -2635,11 +2635,9 @@ typedef jmp_buf sys_jmp_buf; | |||
| 2635 | - The specpdl stack: keeps track of active unwind-protect and | 2635 | - The specpdl stack: keeps track of active unwind-protect and |
| 2636 | dynamic-let-bindings. Allocated from the `specpdl' array, a manually | 2636 | dynamic-let-bindings. Allocated from the `specpdl' array, a manually |
| 2637 | managed stack. | 2637 | managed stack. |
| 2638 | - The catch stack: keeps track of active catch tags. | 2638 | - The handler stack: keeps track of active catch tags and condition-case |
| 2639 | Allocated on the C stack. This is where the setmp data is kept. | 2639 | handlers. Allocated in a manually managed stack implemented by a |
| 2640 | - The handler stack: keeps track of active condition-case handlers. | 2640 | doubly-linked list allocated via xmalloc and never freed. */ |
| 2641 | Allocated on the C stack. Every entry there also uses an entry in | ||
| 2642 | the catch stack. */ | ||
| 2643 | 2641 | ||
| 2644 | /* Structure for recording Lisp call stack for backtrace purposes. */ | 2642 | /* Structure for recording Lisp call stack for backtrace purposes. */ |
| 2645 | 2643 | ||
| @@ -2709,46 +2707,16 @@ SPECPDL_INDEX (void) | |||
| 2709 | return specpdl_ptr - specpdl; | 2707 | return specpdl_ptr - specpdl; |
| 2710 | } | 2708 | } |
| 2711 | 2709 | ||
| 2712 | /* Everything needed to describe an active condition case. | 2710 | /* This structure helps implement the `catch/throw' and `condition-case/signal' |
| 2711 | control structures. A struct handler contains all the information needed to | ||
| 2712 | restore the state of the interpreter after a non-local jump. | ||
| 2713 | 2713 | ||
| 2714 | Members are volatile if their values need to survive _longjmp when | 2714 | handler structures are chained together in a doubly linked list; the `next' |
| 2715 | a 'struct handler' is a local variable. */ | 2715 | member points to the next outer catchtag and the `nextfree' member points in |
| 2716 | struct handler | 2716 | the other direction to the next inner element (which is typically the next |
| 2717 | { | 2717 | free element since we mostly use it on the deepest handler). |
| 2718 | /* The handler clauses and variable from the condition-case form. */ | ||
| 2719 | /* For a handler set up in Lisp code, this is always a list. | ||
| 2720 | For an internal handler set up by internal_condition_case*, | ||
| 2721 | this can instead be the symbol t or `error'. | ||
| 2722 | t: handle all conditions. | ||
| 2723 | error: handle all conditions, and errors can run the debugger | ||
| 2724 | or display a backtrace. */ | ||
| 2725 | Lisp_Object handler; | ||
| 2726 | |||
| 2727 | Lisp_Object volatile var; | ||
| 2728 | |||
| 2729 | /* Fsignal stores here the condition-case clause that applies, | ||
| 2730 | and Fcondition_case thus knows which clause to run. */ | ||
| 2731 | Lisp_Object volatile chosen_clause; | ||
| 2732 | |||
| 2733 | /* Used to effect the longjump out to the handler. */ | ||
| 2734 | struct catchtag *tag; | ||
| 2735 | |||
| 2736 | /* The next enclosing handler. */ | ||
| 2737 | struct handler *next; | ||
| 2738 | }; | ||
| 2739 | 2718 | ||
| 2740 | /* This structure helps implement the `catch' and `throw' control | 2719 | A call like (throw TAG VAL) searches for a catchtag whose `tag_or_ch' |
| 2741 | structure. A struct catchtag contains all the information needed | ||
| 2742 | to restore the state of the interpreter after a non-local jump. | ||
| 2743 | |||
| 2744 | Handlers for error conditions (represented by `struct handler' | ||
| 2745 | structures) just point to a catch tag to do the cleanup required | ||
| 2746 | for their jumps. | ||
| 2747 | |||
| 2748 | catchtag structures are chained together in the C calling stack; | ||
| 2749 | the `next' member points to the next outer catchtag. | ||
| 2750 | |||
| 2751 | A call like (throw TAG VAL) searches for a catchtag whose `tag' | ||
| 2752 | member is TAG, and then unbinds to it. The `val' member is used to | 2720 | member is TAG, and then unbinds to it. The `val' member is used to |
| 2753 | hold VAL while the stack is unwound; `val' is returned as the value | 2721 | hold VAL while the stack is unwound; `val' is returned as the value |
| 2754 | of the catch form. | 2722 | of the catch form. |
| @@ -2757,24 +2725,63 @@ struct handler | |||
| 2757 | state. | 2725 | state. |
| 2758 | 2726 | ||
| 2759 | Members are volatile if their values need to survive _longjmp when | 2727 | Members are volatile if their values need to survive _longjmp when |
| 2760 | a 'struct catchtag' is a local variable. */ | 2728 | a 'struct handler' is a local variable. */ |
| 2761 | struct catchtag | 2729 | |
| 2730 | enum handlertype { CATCHER, CONDITION_CASE }; | ||
| 2731 | |||
| 2732 | struct handler | ||
| 2762 | { | 2733 | { |
| 2763 | Lisp_Object tag; | 2734 | enum handlertype type; |
| 2764 | Lisp_Object volatile val; | 2735 | Lisp_Object tag_or_ch; |
| 2765 | struct catchtag *volatile next; | 2736 | Lisp_Object val; |
| 2737 | struct handler *next; | ||
| 2738 | struct handler *nextfree; | ||
| 2739 | |||
| 2740 | /* The bytecode interpreter can have several handlers active at the same | ||
| 2741 | time, so when we longjmp to one of them, it needs to know which handler | ||
| 2742 | this was and what was the corresponding internal state. This is stored | ||
| 2743 | here, and when we longjmp we make sure that handlerlist points to the | ||
| 2744 | proper handler. */ | ||
| 2745 | Lisp_Object *bytecode_top; | ||
| 2746 | int bytecode_dest; | ||
| 2747 | |||
| 2748 | /* Most global vars are reset to their value via the specpdl mechanism, | ||
| 2749 | but a few others are handled by storing their value here. */ | ||
| 2766 | #if 1 /* GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS, but they're defined later. */ | 2750 | #if 1 /* GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS, but they're defined later. */ |
| 2767 | struct gcpro *gcpro; | 2751 | struct gcpro *gcpro; |
| 2768 | #endif | 2752 | #endif |
| 2769 | sys_jmp_buf jmp; | 2753 | sys_jmp_buf jmp; |
| 2770 | struct handler *handlerlist; | ||
| 2771 | EMACS_INT lisp_eval_depth; | 2754 | EMACS_INT lisp_eval_depth; |
| 2772 | ptrdiff_t volatile pdlcount; | 2755 | ptrdiff_t pdlcount; |
| 2773 | int poll_suppress_count; | 2756 | int poll_suppress_count; |
| 2774 | int interrupt_input_blocked; | 2757 | int interrupt_input_blocked; |
| 2775 | struct byte_stack *byte_stack; | 2758 | struct byte_stack *byte_stack; |
| 2776 | }; | 2759 | }; |
| 2777 | 2760 | ||
| 2761 | /* Fill in the components of c, and put it on the list. */ | ||
| 2762 | #define PUSH_HANDLER(c, tag_ch_val, handlertype) \ | ||
| 2763 | if (handlerlist && handlerlist->nextfree) \ | ||
| 2764 | (c) = handlerlist->nextfree; \ | ||
| 2765 | else \ | ||
| 2766 | { \ | ||
| 2767 | (c) = xmalloc (sizeof (struct handler)); \ | ||
| 2768 | (c)->nextfree = NULL; \ | ||
| 2769 | if (handlerlist) \ | ||
| 2770 | handlerlist->nextfree = (c); \ | ||
| 2771 | } \ | ||
| 2772 | (c)->type = (handlertype); \ | ||
| 2773 | (c)->tag_or_ch = (tag_ch_val); \ | ||
| 2774 | (c)->val = Qnil; \ | ||
| 2775 | (c)->next = handlerlist; \ | ||
| 2776 | (c)->lisp_eval_depth = lisp_eval_depth; \ | ||
| 2777 | (c)->pdlcount = SPECPDL_INDEX (); \ | ||
| 2778 | (c)->poll_suppress_count = poll_suppress_count; \ | ||
| 2779 | (c)->interrupt_input_blocked = interrupt_input_blocked;\ | ||
| 2780 | (c)->gcpro = gcprolist; \ | ||
| 2781 | (c)->byte_stack = byte_stack_list; \ | ||
| 2782 | handlerlist = (c); | ||
| 2783 | |||
| 2784 | |||
| 2778 | extern Lisp_Object memory_signal_data; | 2785 | extern Lisp_Object memory_signal_data; |
| 2779 | 2786 | ||
| 2780 | /* An address near the bottom of the stack. | 2787 | /* An address near the bottom of the stack. |
| @@ -3677,10 +3684,8 @@ extern Lisp_Object Qand_rest; | |||
| 3677 | extern Lisp_Object Vautoload_queue; | 3684 | extern Lisp_Object Vautoload_queue; |
| 3678 | extern Lisp_Object Vsignaling_function; | 3685 | extern Lisp_Object Vsignaling_function; |
| 3679 | extern Lisp_Object inhibit_lisp_code; | 3686 | extern Lisp_Object inhibit_lisp_code; |
| 3680 | #if BYTE_MARK_STACK | ||
| 3681 | extern struct catchtag *catchlist; | ||
| 3682 | extern struct handler *handlerlist; | 3687 | extern struct handler *handlerlist; |
| 3683 | #endif | 3688 | |
| 3684 | /* To run a normal hook, use the appropriate function from the list below. | 3689 | /* To run a normal hook, use the appropriate function from the list below. |
| 3685 | The calling convention: | 3690 | The calling convention: |
| 3686 | 3691 | ||