Faster, more compact, and readable closure creation

Simplify closure creation by calling a single function at run time
instead of putting it together from small pieces.  This is faster
(by about a factor 2), takes less space on disk and in memory, and
makes internal functions somewhat readable in disassembly listings again.

This is done by creating a prototype function at compile-time whose
closure variables are placeholder values V0, V1... which can be seen
in the disassembly.  The prototype is then cloned at run time using
the new make-closure function that replaces the placeholders with
the actual closure variables.

* lisp/emacs-lisp/bytecomp.el (byte-compile-make-closure):
Generate call to make-closure from a prototype function.
* src/alloc.c (Fmake_closure): New function.
(syms_of_alloc): Defsubr it.
* src/data.c (syms_of_data): Defsym byte-code-function-p.
This commit is contained in:
Mattias Engdegård 2021-02-21 15:24:41 +01:00
parent 2790c6a572
commit d0c47652e5
3 changed files with 50 additions and 9 deletions

View file

@ -3817,15 +3817,21 @@ discarding."
(cl-assert (or (> (length env) 0)
docstring-exp)) ;Otherwise, we don't need a closure.
(cl-assert (byte-code-function-p fun))
(byte-compile-form `(make-byte-code
',(aref fun 0) ',(aref fun 1)
(vconcat (vector . ,env) ',(aref fun 2))
,@(let ((rest (nthcdr 3 (mapcar (lambda (x) `',x) fun))))
(if docstring-exp
`(,(car rest)
,docstring-exp
,@(cddr rest))
rest)))))))
(byte-compile-form
;; Use symbols V0, V1 ... as placeholders for closure variables:
;; they should be short (to save space in the .elc file), yet
;; distinct when disassembled.
(let* ((dummy-vars (mapcar (lambda (i) (intern (format "V%d" i)))
(number-sequence 0 (1- (length env)))))
(proto-fun
(apply #'make-byte-code
(aref fun 0) (aref fun 1)
;; Prepend dummy cells to the constant vector,
;; to get the indices right when disassembling.
(vconcat dummy-vars (aref fun 2))
(mapcar (lambda (i) (aref fun i))
(number-sequence 3 (1- (length fun)))))))
`(make-closure ,proto-fun ,@env))))))
(defun byte-compile-get-closed-var (form)
"Byte-compile the special `internal-get-closed-var' form."