mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-15 10:30:25 -08:00
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.
This commit is contained in:
parent
328a8179fe
commit
adf2aa6140
9 changed files with 475 additions and 306 deletions
|
|
@ -79,8 +79,7 @@
|
|||
;; command-history).
|
||||
;; - canonize code in macro-expand so we don't have to handle (let (var) body)
|
||||
;; and other oddities.
|
||||
;; - new byte codes for unwind-protect, catch, and condition-case so that
|
||||
;; closures aren't needed at all.
|
||||
;; - new byte codes for unwind-protect so that closures aren't needed at all.
|
||||
;; - a reference to a var that is known statically to always hold a constant
|
||||
;; should be turned into a byte-constant rather than a byte-stack-ref.
|
||||
;; Hmm... right, that's called constant propagation and could be done here,
|
||||
|
|
@ -421,18 +420,42 @@ places where they originally did not directly appear."
|
|||
forms)))
|
||||
|
||||
;condition-case
|
||||
(`(condition-case ,var ,protected-form . ,handlers)
|
||||
((and `(condition-case ,var ,protected-form . ,handlers)
|
||||
(guard byte-compile--use-old-handlers))
|
||||
(let ((newform (cconv--convert-function
|
||||
() (list protected-form) env form)))
|
||||
`(condition-case :fun-body ,newform
|
||||
,@(mapcar (lambda (handler)
|
||||
,@(mapcar (lambda (handler)
|
||||
(list (car handler)
|
||||
(cconv--convert-function
|
||||
(list (or var cconv--dummy-var))
|
||||
(cdr handler) env form)))
|
||||
handlers))))
|
||||
|
||||
(`(,(and head (or `catch `unwind-protect)) ,form . ,body)
|
||||
; condition-case with new byte-codes.
|
||||
(`(condition-case ,var ,protected-form . ,handlers)
|
||||
`(condition-case ,var
|
||||
,(cconv-convert protected-form env extend)
|
||||
,@(let* ((cm (and var (member (cons (list var) form)
|
||||
cconv-captured+mutated)))
|
||||
(newenv
|
||||
(cond (cm (cons `(,var . (car-save ,var)) env))
|
||||
((assq var env) (cons `(,var) env))
|
||||
(t env))))
|
||||
(mapcar
|
||||
(lambda (handler)
|
||||
`(,(car handler)
|
||||
,@(let ((body
|
||||
(mapcar (lambda (form)
|
||||
(cconv-convert form newenv extend))
|
||||
(cdr handler))))
|
||||
(if (not cm) body
|
||||
`((let ((,var (list ,var))) ,@body))))))
|
||||
handlers))))
|
||||
|
||||
(`(,(and head (or (and `catch (guard byte-compile--use-old-handlers))
|
||||
`unwind-protect))
|
||||
,form . ,body)
|
||||
`(,head ,(cconv-convert form env extend)
|
||||
:fun-body ,(cconv--convert-function () body env form)))
|
||||
|
||||
|
|
@ -491,7 +514,7 @@ places where they originally did not directly appear."
|
|||
|
||||
(`(,func . ,forms)
|
||||
;; First element is function or whatever function-like forms are: or, and,
|
||||
;; if, progn, prog1, prog2, while, until
|
||||
;; if, catch, progn, prog1, prog2, while, until
|
||||
`(,func . ,(mapcar (lambda (form)
|
||||
(cconv-convert form env extend))
|
||||
forms)))
|
||||
|
|
@ -646,16 +669,32 @@ and updates the data stored in ENV."
|
|||
(`(quote . ,_) nil) ; quote form
|
||||
(`(function . ,_) nil) ; same as quote
|
||||
|
||||
(`(condition-case ,var ,protected-form . ,handlers)
|
||||
((and `(condition-case ,var ,protected-form . ,handlers)
|
||||
(guard byte-compile--use-old-handlers))
|
||||
;; FIXME: The bytecode for condition-case forces us to wrap the
|
||||
;; form and handlers in closures (for handlers, it's understandable
|
||||
;; but not for the protected form).
|
||||
;; form and handlers in closures.
|
||||
(cconv--analyse-function () (list protected-form) env form)
|
||||
(dolist (handler handlers)
|
||||
(cconv--analyse-function (if var (list var)) (cdr handler) env form)))
|
||||
(cconv--analyse-function (if var (list var)) (cdr handler)
|
||||
env form)))
|
||||
|
||||
;; FIXME: The bytecode for catch forces us to wrap the body.
|
||||
(`(,(or `catch `unwind-protect) ,form . ,body)
|
||||
(`(condition-case ,var ,protected-form . ,handlers)
|
||||
(cconv-analyse-form protected-form env)
|
||||
(when (and var (symbolp var) (byte-compile-not-lexical-var-p var))
|
||||
(byte-compile-log-warning
|
||||
(format "Lexical variable shadows the dynamic variable %S" var)))
|
||||
(let* ((varstruct (list var nil nil nil nil)))
|
||||
(if var (push varstruct env))
|
||||
(dolist (handler handlers)
|
||||
(dolist (form (cdr handler))
|
||||
(cconv-analyse-form form env)))
|
||||
(if var (cconv--analyse-use (cons (list var) (cdr varstruct))
|
||||
form "variable"))))
|
||||
|
||||
;; FIXME: The bytecode for unwind-protect forces us to wrap the unwind.
|
||||
(`(,(or (and `catch (guard byte-compile--use-old-handlers))
|
||||
`unwind-protect)
|
||||
,form . ,body)
|
||||
(cconv-analyse-form form env)
|
||||
(cconv--analyse-function () body env form))
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue