mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-06 22:41:06 -08:00
(Ffunction): Make interpreted closures safe for space
Interpreted closures currently just grab a reference to the complete
lexical environment, so (lambda (x) (+ x y)) can end up looking like
(closure ((foo ...) (y 7) (bar ...) ...)
(x) (+ x y))
where the foo/bar/... bindings are not only useless but can prevent
the GC from collecting that memory (i.e. it's a representation that is
not "safe for space") and it can also make that closure "unwritable"
(or more specifically, it can cause the closure's print
representation to be u`read`able).
Compiled closures don't suffer from this problem because `cconv.el`
actually looks at the code and only stores in the compiled closure
those variables which are actually used.
So, we fix this discrepancy by letting the existing code in `cconv.el` tell
`Ffunction` which variables are actually used by the body of the
function such that it can filter out the irrelevant elements and
return a closure of the form:
(closure ((y 7)) (x) (+ x y))
* lisp/loadup.el: Preload `cconv` and set
`internal-filter-closure-env-function` once we have a usable `cconv-fv`.
* lisp/emacs-lisp/bytecomp.el (byte-compile-preprocess): Adjust to new
calling convention of `cconv-closure-convert`.
(byte-compile-not-lexical-var-p): Delete function, moved to `cconv.el`.
(byte-compile-bind): Use `cconv--not-lexical-var-p`.
* lisp/emacs-lisp/cconv.el (cconv--dynbound-variables): New var.
(cconv-closure-convert): New arg `dynbound-vars`
(cconv--warn-unused-msg): Remove special case for `ignored`,
so we don't get confused when a function uses an argument called
`ignored`, e.g. holding a list of things that it should ignore.
(cconv--not-lexical-var-p): New function, moved from `bytecomp.el`.
Don't special case keywords and `nil` and `t` since they are already
`special-variable-p`.
(cconv--analyze-function): Use `cconv--not-lexical-var-p`.
(cconv--dynbindings): New dynbound var.
(cconv-analyze-form): Use `cconv--not-lexical-var-p`.
Remember in `cconv--dynbindings` the vars for which we used
dynamic scoping.
(cconv-analyze-form): Use `cconv--dynbound-variables` rather than
`byte-compile-bound-variables`.
(cconv-fv): New function.
* src/eval.c (Fsetq, eval_sub): Remove optimization designed when
`lexical-binding == nil` was the common case.
(Ffunction): Use `internal-filter-closure-env-function` when available.
(eval_sub, Ffuncall): Improve error info for `excessive_lisp_nesting`.
(internal-filter-closure-env-function): New defvar.
This commit is contained in:
parent
7e60246ab3
commit
1b1ffe0789
6 changed files with 107 additions and 65 deletions
|
|
@ -2565,7 +2565,7 @@ list that represents a doc string reference.
|
|||
;; macroexpand-all.
|
||||
;; (if (memq byte-optimize '(t source))
|
||||
;; (setq form (byte-optimize-form form for-effect)))
|
||||
(cconv-closure-convert form))
|
||||
(cconv-closure-convert form byte-compile-bound-variables))
|
||||
|
||||
;; byte-hunk-handlers cannot call this!
|
||||
(defun byte-compile-toplevel-file-form (top-level-form)
|
||||
|
|
@ -4663,13 +4663,6 @@ Return the offset in the form (VAR . OFFSET)."
|
|||
(byte-compile-form (cadr clause))
|
||||
(byte-compile-push-constant nil)))))
|
||||
|
||||
(defun byte-compile-not-lexical-var-p (var)
|
||||
(or (not (symbolp var))
|
||||
(special-variable-p var)
|
||||
(memq var byte-compile-bound-variables)
|
||||
(memq var '(nil t))
|
||||
(keywordp var)))
|
||||
|
||||
(defun byte-compile-bind (var init-lexenv)
|
||||
"Emit byte-codes to bind VAR and update `byte-compile--lexical-environment'.
|
||||
INIT-LEXENV should be a lexical-environment alist describing the
|
||||
|
|
@ -4678,7 +4671,7 @@ Return non-nil if the TOS value was popped."
|
|||
;; The mix of lexical and dynamic bindings mean that we may have to
|
||||
;; juggle things on the stack, to move them to TOS for
|
||||
;; dynamic binding.
|
||||
(if (and lexical-binding (not (byte-compile-not-lexical-var-p var)))
|
||||
(if (not (cconv--not-lexical-var-p var byte-compile-bound-variables))
|
||||
;; VAR is a simple stack-allocated lexical variable.
|
||||
(progn (push (assq var init-lexenv)
|
||||
byte-compile--lexical-environment)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue