* Speed of Byte-Code:: An example of speedup from byte compilation.
* Compilation Functions:: Byte compilation functions.
* Docs and Compilation:: Dynamic loading of documentation strings.
-* Dynamic Loading:: Dynamic loading of individual functions.
* Eval During Compile:: Code to be evaluated when you compile.
* Compiler Errors:: Handling compiler error messages.
* Byte-Code Objects:: The data type used for byte-compiled functions.
constructs in Lisp source files; they are not designed to be clear to
humans reading the file.
-@node Dynamic Loading
-@section Dynamic Loading of Individual Functions
-
-@cindex dynamic loading of functions
-@cindex lazy loading
- When you compile a file, you can optionally enable the @dfn{dynamic
-function loading} feature (also known as @dfn{lazy loading}). With
-dynamic function loading, loading the file doesn't fully read the
-function definitions in the file. Instead, each function definition
-contains a place-holder which refers to the file. The first time each
-function is called, it reads the full definition from the file, to
-replace the place-holder.
-
- The advantage of dynamic function loading is that loading the file
-should become faster. This is a good thing for a file which contains
-many separate user-callable functions, if using one of them does not
-imply you will probably also use the rest. A specialized mode which
-provides many keyboard commands often has that usage pattern: a user may
-invoke the mode, but use only a few of the commands it provides.
-
- The dynamic loading feature has certain disadvantages:
-
-@itemize @bullet
-@item
-If you delete or move the compiled file after loading it, Emacs can no
-longer load the remaining function definitions not already loaded.
-
-@item
-If you alter the compiled file (such as by compiling a new version),
-then trying to load any function not already loaded will usually yield
-nonsense results.
-@end itemize
-
- These problems will never happen in normal circumstances with
-installed Emacs files. But they are quite likely to happen with Lisp
-files that you are changing. The easiest way to prevent these problems
-is to reload the new compiled file immediately after each recompilation.
-
- @emph{Experience shows that using dynamic function loading provides
-benefits that are hardly measurable, so this feature is deprecated
-since Emacs 27.1.}
-
- The byte compiler uses the dynamic function loading feature if the
-variable @code{byte-compile-dynamic} is non-@code{nil} at compilation
-time. Do not set this variable globally, since dynamic loading is
-desirable only for certain files. Instead, enable the feature for
-specific source files with file-local variable bindings. For example,
-you could do it by writing this text in the source file's first line:
-
-@example
--*-byte-compile-dynamic: t;-*-
-@end example
-
-@defvar byte-compile-dynamic
-If this is non-@code{nil}, the byte compiler generates compiled files
-that are set up for dynamic function loading.
-@end defvar
-
-@defun fetch-bytecode function
-If @var{function} is a byte-code function object, this immediately
-finishes loading the byte code of @var{function} from its
-byte-compiled file, if it is not fully loaded already. Otherwise,
-it does nothing. It always returns @var{function}.
-@end defun
-
@node Eval During Compile
@section Evaluation During Compilation
@cindex eval during compilation
* Speed of Byte-Code:: An example of speedup from byte compilation.
* Compilation Functions:: Byte compilation functions.
* Docs and Compilation:: Dynamic loading of documentation strings.
-* Dynamic Loading:: Dynamic loading of individual functions.
* Eval During Compile:: Code to be evaluated when you compile.
* Compiler Errors:: Handling compiler error messages.
* Byte-Code Objects:: The data type used for byte-compiled functions.
'important-return-value' property which indicates that the function
return value should probably not be thrown away implicitly.
+** Bytecode is now always loaded eagerly.
+Bytecode compiled with older Emacs versions for lazy loading using
+'byte-compile-dynamic' is now loaded all at once.
+As a consequence, 'fetch-bytecode' has no use, does nothing, and is
+now obsolete. The variable 'byte-compile-dynamic' has no effect any
+more; compilation will always yield bytecode for eager loading.
+
+++
** New functions 'file-user-uid' and 'file-group-gid'.
These functions are like 'user-uid' and 'group-gid', respectively, but
:type 'boolean)
(defvar byte-compile-dynamic nil
- "If non-nil, compile function bodies so they load lazily.
-They are hidden in comments in the compiled file,
-and each one is brought into core when the
-function is called.
-
-To enable this option, make it a file-local variable
-in the source file you want it to apply to.
-For example, add -*-byte-compile-dynamic: t;-*- on the first line.
-
-When this option is true, if you load the compiled file and then move it,
-the functions you loaded will not be able to run.")
+ "Formerly used to compile function bodies so they load lazily.
+This variable no longer has any effect.")
(make-obsolete-variable 'byte-compile-dynamic "not worthwhile any more." "27.1")
;;;###autoload(put 'byte-compile-dynamic 'safe-local-variable 'booleanp)
;;
(byte-compile-verbose byte-compile-verbose)
(byte-optimize byte-optimize)
- (byte-compile-dynamic byte-compile-dynamic)
(byte-compile-dynamic-docstrings
byte-compile-dynamic-docstrings)
(byte-compile-warnings byte-compile-warnings)
(defun byte-compile-insert-header (_filename outbuffer)
"Insert a header at the start of OUTBUFFER.
Call from the source buffer."
- (let ((dynamic byte-compile-dynamic)
- (optimize byte-optimize))
+ (let ((optimize byte-optimize))
(with-current-buffer outbuffer
(goto-char (point-min))
;; The magic number of .elc files is ";ELC", or 0x3B454C43. After
((eq optimize 'byte) " byte-level optimization only")
(optimize " all optimizations")
(t "out optimization"))
- ".\n"
- (if dynamic ";;; Function definitions are lazy-loaded.\n"
- "")
- "\n\n"))))
+ ".\n\n\n"))))
(defun byte-compile-output-file-form (form)
;; Write the given form to the output buffer, being careful of docstrings
(print-circle t)) ; Handle circular data structures.
(if (memq (car-safe form) '(defvar defvaralias defconst
autoload custom-declare-variable))
- (byte-compile-output-docform nil nil nil '("\n(" ")") form nil 3 nil
+ (byte-compile-output-docform nil nil nil '("\n(" ")") form nil 3
(memq (car form)
'(defvaralias autoload
custom-declare-variable)))
(defvar byte-compile--for-effect)
(defun byte-compile--output-docform-recurse
- (info position form cvecindex docindex specindex quoted)
+ (info position form cvecindex docindex quoted)
"Print a form with a doc string. INFO is (prefix postfix).
POSITION is where the next doc string is to be inserted.
CVECINDEX is the index in the FORM of the constant vector, or nil.
DOCINDEX is the index of the doc string (or nil) in the FORM.
-If SPECINDEX is non-nil, it is the index in FORM
-of the function bytecode string. In that case,
-we output that argument and the following argument
-\(the constants vector) together, for lazy loading.
QUOTED says that we have to put a quote before the
list that represents a doc string reference.
`defvaralias', `autoload' and `custom-declare-variable' need that.
(while (setq form (cdr form))
(setq index (1+ index))
(insert " ")
- (cond ((and (numberp specindex) (= index specindex)
- ;; Don't handle the definition dynamically
- ;; if it refers (or might refer)
- ;; to objects already output
- ;; (for instance, gensyms in the arg list).
- (let (non-nil)
- (when (hash-table-p print-number-table)
- (maphash (lambda (_k v) (if v (setq non-nil t)))
- print-number-table))
- (not non-nil)))
- ;; Output the byte code and constants specially
- ;; for lazy dynamic loading.
- (goto-char position)
- (let ((lazy-position (byte-compile-output-as-comment
- (cons (car form) (nth 1 form))
- t)))
- (setq position (point))
- (goto-char (point-max))
- (princ (format "(#$ . %d) nil" lazy-position)
- byte-compile--outbuffer)
- (setq form (cdr form))
- (setq index (1+ index))))
- ((eq index cvecindex)
+ (cond ((eq index cvecindex)
(let* ((cvec (car form))
(len (length cvec))
(index2 0)
(byte-compile--output-docform-recurse
'("#[" "]") position
(append elt nil) ; Convert the vector to a list.
- 2 4 specindex nil))
+ 2 4 nil))
(prin1 elt byte-compile--outbuffer))
(setq index2 (1+ index2))
(unless (eq index2 len)
(defun byte-compile-output-docform (preface tailpiece name info form
cvecindex docindex
- specindex quoted)
+ quoted)
"Print a form with a doc string. INFO is (prefix postfix).
If PREFACE, NAME, and TAILPIECE are non-nil, print them too,
before/after INFO and the FORM but after the doc string itself.
CVECINDEX is the index in the FORM of the constant vector, or nil.
DOCINDEX is the index of the doc string (or nil) in the FORM.
-If SPECINDEX is non-nil, it is the index in FORM
-of the function bytecode string. In that case,
-we output that argument and the following argument
-\(the constants vector) together, for lazy loading.
QUOTED says that we have to put a quote before the
list that represents a doc string reference.
`defvaralias', `autoload' and `custom-declare-variable' need that."
(insert preface)
(prin1 name byte-compile--outbuffer))
(byte-compile--output-docform-recurse
- info position form cvecindex docindex specindex quoted)
+ info position form cvecindex docindex quoted)
(when tailpiece
(insert tailpiece))))))
(if macro '(" '(macro . #[" "])") '(" #[" "]"))
(append code nil) ; Turn byte-code-function-p into list.
2 4
- (and (atom code) byte-compile-dynamic 1)
nil)
t)))))
(alen (length (cdr form)))
(dynbinds ())
lap)
- (fetch-bytecode fun)
(setq lap (byte-decompile-bytecode-1 (aref fun 1) (aref fun 2) t))
;; optimized switch bytecode makes it impossible to guess the correct
;; `byte-compile-depth', which can result in incorrect inlined code.
(if (consp obj)
(setq bytes (car (cdr obj)) ;the byte code
constvec (car (cdr (cdr obj)))) ;constant vector
- ;; If it is lazy-loaded, load it now
- (fetch-bytecode obj)
(setq bytes (aref obj 1)
constvec (aref obj 2)))
(cl-assert (not (multibyte-string-p bytes)))
(defvaralias 'native-comp-deferred-compilation 'native-comp-jit-compilation)
+(define-obsolete-function-alias 'fetch-bytecode #'ignore "30.1")
+
\f
;;;; Alternate names for functions - these are not being phased out.
Lisp_Object original_fun = call_fun;
if (SYMBOLP (call_fun))
call_fun = XSYMBOL (call_fun)->u.s.function;
- Lisp_Object template;
- Lisp_Object bytecode;
- if (COMPILEDP (call_fun)
- /* Lexical binding only. */
- && (template = AREF (call_fun, COMPILED_ARGLIST),
- FIXNUMP (template))
- /* No autoloads. */
- && (bytecode = AREF (call_fun, COMPILED_BYTECODE),
- !CONSP (bytecode)))
+ if (COMPILEDP (call_fun))
{
- fun = call_fun;
- bytestr = bytecode;
- args_template = XFIXNUM (template);
- nargs = call_nargs;
- args = call_args;
- goto setup_frame;
+ Lisp_Object template = AREF (call_fun, COMPILED_ARGLIST);
+ if (FIXNUMP (template))
+ {
+ /* Fast path for lexbound functions. */
+ fun = call_fun;
+ bytestr = AREF (call_fun, COMPILED_BYTECODE),
+ args_template = XFIXNUM (template);
+ nargs = call_nargs;
+ args = call_args;
+ goto setup_frame;
+ }
}
Lisp_Object val;
xsignal2 (Qwrong_number_of_arguments, fun, make_fixnum (numargs));
}
-/* Call the compiled Lisp function FUN. If we have not yet read FUN's
- bytecode string and constants vector, fetch them from the file first. */
-
-static Lisp_Object
-fetch_and_exec_byte_code (Lisp_Object fun, ptrdiff_t args_template,
- ptrdiff_t nargs, Lisp_Object *args)
-{
- if (CONSP (AREF (fun, COMPILED_BYTECODE)))
- Ffetch_bytecode (fun);
-
- return exec_byte_code (fun, args_template, nargs, args);
-}
-
static Lisp_Object
apply_lambda (Lisp_Object fun, Lisp_Object args, specpdl_ref count)
{
ARGLIST slot value: pass the arguments to the byte-code
engine directly. */
if (FIXNUMP (syms_left))
- return fetch_and_exec_byte_code (fun, XFIXNUM (syms_left),
- nargs, arg_vector);
+ return exec_byte_code (fun, XFIXNUM (syms_left), nargs, arg_vector);
/* Otherwise the bytecode object uses dynamic binding and the
ARGLIST slot contains a standard formal argument list whose
variables are bound dynamically below. */
val = XSUBR (fun)->function.a0 ();
}
else
- val = fetch_and_exec_byte_code (fun, 0, 0, NULL);
+ val = exec_byte_code (fun, 0, 0, NULL);
return unbind_to (count, val);
}
return Fcons (make_fixnum (minargs), make_fixnum (maxargs));
}
-DEFUN ("fetch-bytecode", Ffetch_bytecode, Sfetch_bytecode,
- 1, 1, 0,
- doc: /* If byte-compiled OBJECT is lazy-loaded, fetch it now. */)
- (Lisp_Object object)
-{
- Lisp_Object tem;
-
- if (COMPILEDP (object))
- {
- if (CONSP (AREF (object, COMPILED_BYTECODE)))
- {
- tem = read_doc_string (AREF (object, COMPILED_BYTECODE));
- if (! (CONSP (tem) && STRINGP (XCAR (tem))
- && VECTORP (XCDR (tem))))
- {
- tem = AREF (object, COMPILED_BYTECODE);
- if (CONSP (tem) && STRINGP (XCAR (tem)))
- error ("Invalid byte code in %s", SDATA (XCAR (tem)));
- else
- error ("Invalid byte code");
- }
-
- Lisp_Object bytecode = XCAR (tem);
- if (STRING_MULTIBYTE (bytecode))
- {
- /* BYTECODE must have been produced by Emacs 20.2 or earlier
- because it produced a raw 8-bit string for byte-code and now
- such a byte-code string is loaded as multibyte with raw 8-bit
- characters converted to multibyte form. Convert them back to
- the original unibyte form. */
- bytecode = Fstring_as_unibyte (bytecode);
- }
-
- pin_string (bytecode);
- ASET (object, COMPILED_BYTECODE, bytecode);
- ASET (object, COMPILED_CONSTANTS, XCDR (tem));
- }
- }
- return object;
-}
\f
/* Return true if SYMBOL's default currently has a let-binding
which was made in the buffer that is now current. */
defsubr (&Srun_hook_with_args_until_success);
defsubr (&Srun_hook_with_args_until_failure);
defsubr (&Srun_hook_wrapped);
- defsubr (&Sfetch_bytecode);
defsubr (&Sbacktrace_debug);
DEFSYM (QCdebug_on_exit, ":debug-on-exit");
defsubr (&Smapbacktrace);
return obj;
}
+static Lisp_Object get_lazy_string (Lisp_Object val);
+
static Lisp_Object
bytecode_from_rev_list (Lisp_Object elems, Lisp_Object readcharfun)
{
&& FIXNATP (vec[COMPILED_STACK_DEPTH])))
invalid_syntax ("Invalid byte-code object", readcharfun);
- if (load_force_doc_strings
- && NILP (vec[COMPILED_CONSTANTS])
- && STRINGP (vec[COMPILED_BYTECODE]))
+ /* Always read 'lazily-loaded' bytecode (generated by the
+ `byte-compile-dynamic' feature prior to Emacs 30) eagerly, to
+ avoid code in the fast path during execution. */
+ if (CONSP (vec[COMPILED_BYTECODE]))
+ vec[COMPILED_BYTECODE] = get_lazy_string (vec[COMPILED_BYTECODE]);
+
+ /* Lazily-loaded bytecode is represented by the constant slot being nil
+ and the bytecode slot a (lazily loaded) string containing the
+ print representation of (BYTECODE . CONSTANTS). Unpack the
+ pieces by coerceing the string to unibyte and reading the result. */
+ if (NILP (vec[COMPILED_CONSTANTS]))
{
- /* Lazily-loaded bytecode is represented by the constant slot being nil
- and the bytecode slot a (lazily loaded) string containing the
- print representation of (BYTECODE . CONSTANTS). Unpack the
- pieces by coerceing the string to unibyte and reading the result. */
Lisp_Object enc = vec[COMPILED_BYTECODE];
Lisp_Object pair = Fread (Fcons (enc, readcharfun));
if (!CONSP (pair))
vec[COMPILED_CONSTANTS] = XCDR (pair);
}
- if (!((STRINGP (vec[COMPILED_BYTECODE])
- && VECTORP (vec[COMPILED_CONSTANTS]))
- || CONSP (vec[COMPILED_BYTECODE])))
+ if (!(STRINGP (vec[COMPILED_BYTECODE])
+ && VECTORP (vec[COMPILED_CONSTANTS])))
invalid_syntax ("Invalid byte-code object", readcharfun);
- if (STRINGP (vec[COMPILED_BYTECODE]))
- {
- if (STRING_MULTIBYTE (vec[COMPILED_BYTECODE]))
- {
- /* BYTESTR must have been produced by Emacs 20.2 or earlier
- because it produced a raw 8-bit string for byte-code and
- now such a byte-code string is loaded as multibyte with
- raw 8-bit characters converted to multibyte form.
- Convert them back to the original unibyte form. */
- vec[COMPILED_BYTECODE] = Fstring_as_unibyte (vec[COMPILED_BYTECODE]);
- }
- /* Bytecode must be immovable. */
- pin_string (vec[COMPILED_BYTECODE]);
- }
+ if (STRING_MULTIBYTE (vec[COMPILED_BYTECODE]))
+ /* BYTESTR must have been produced by Emacs 20.2 or earlier
+ because it produced a raw 8-bit string for byte-code and
+ now such a byte-code string is loaded as multibyte with
+ raw 8-bit characters converted to multibyte form.
+ Convert them back to the original unibyte form. */
+ vec[COMPILED_BYTECODE] = Fstring_as_unibyte (vec[COMPILED_BYTECODE]);
+
+ /* Bytecode must be immovable. */
+ pin_string (vec[COMPILED_BYTECODE]);
XSETPVECTYPE (XVECTOR (obj), PVEC_COMPILED);
return obj;