(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."
return val;
}
+DEFUN ("make-closure", Fmake_closure, Smake_closure, 1, MANY, 0,
+ doc: /* Create a byte-code closure from PROTOTYPE and CLOSURE-VARS.
+Return a copy of PROTOTYPE, a byte-code object, with CLOSURE-VARS
+replacing the elements in the beginning of the constant-vector.
+usage: (make-closure PROTOTYPE &rest CLOSURE-VARS) */)
+ (ptrdiff_t nargs, Lisp_Object *args)
+{
+ Lisp_Object protofun = args[0];
+ CHECK_TYPE (COMPILEDP (protofun), Qbyte_code_function_p, protofun);
+
+ /* Create a copy of the constant vector, filling it with the closure
+ variables in the beginning. (The overwritten part should just
+ contain placeholder values.) */
+ Lisp_Object proto_constvec = AREF (protofun, COMPILED_CONSTANTS);
+ ptrdiff_t constsize = ASIZE (proto_constvec);
+ ptrdiff_t nvars = nargs - 1;
+ if (nvars > constsize)
+ error ("Closure vars do not fit in constvec");
+ Lisp_Object constvec = make_uninit_vector (constsize);
+ memcpy (XVECTOR (constvec)->contents, args + 1, nvars * word_size);
+ memcpy (XVECTOR (constvec)->contents + nvars,
+ XVECTOR (proto_constvec)->contents + nvars,
+ (constsize - nvars) * word_size);
+
+ /* Return a copy of the prototype function with the new constant vector. */
+ ptrdiff_t protosize = PVSIZE (protofun);
+ struct Lisp_Vector *v = allocate_vectorlike (protosize, false);
+ v->header = XVECTOR (protofun)->header;
+ memcpy (v->contents, XVECTOR (protofun)->contents, protosize * word_size);
+ v->contents[COMPILED_CONSTANTS] = constvec;
+ return make_lisp_ptr (v, Lisp_Vectorlike);
+}
\f
/***********************************************************************
defsubr (&Srecord);
defsubr (&Sbool_vector);
defsubr (&Smake_byte_code);
+ defsubr (&Smake_closure);
defsubr (&Smake_list);
defsubr (&Smake_vector);
defsubr (&Smake_record);
DEFSYM (Qinteractive_form, "interactive-form");
DEFSYM (Qdefalias_fset_function, "defalias-fset-function");
+ DEFSYM (Qbyte_code_function_p, "byte-code-function-p");
+
defsubr (&Sindirect_variable);
defsubr (&Sinteractive_form);
defsubr (&Scommand_modes);