aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMattias EngdegÄrd2024-01-30 17:55:19 +0100
committerMattias EngdegÄrd2024-01-31 17:12:25 +0100
commit9bcc9690a8076a22398c27a7ccf836ee95eb16a2 (patch)
tree8cc52b73bc6428f74da2c94c83990b01ce7032be /src
parent7e85311a9113a4720ec9d7b06188646fc7bdae0b (diff)
downloademacs-9bcc9690a8076a22398c27a7ccf836ee95eb16a2.tar.gz
emacs-9bcc9690a8076a22398c27a7ccf836ee95eb16a2.zip
Eliminate lazy bytecode loading
The obsolete lazy-loaded bytecode feature, enabled by `byte-compile-dynamic`, slows down Lisp execution even when not in use because every call to a bytecode function has to check that function for laziness. This change forces up-front loading of all lazy bytecode so that we can remove all those checks. (Dynamically loaded doc strings are not affected.) There is no point in generating lazy bytecode any more so we stop doing that; this simplifies the compiler. `byte-compile-dynamic` now has no effect. This is a fully compatible change; the few remaining users of `byte-compile-dynamic` should not notice any difference. * src/lread.c (bytecode_from_rev_list): Force eager loading of lazy bytecode. * src/bytecode.c (exec_byte_code): Remove lazy bytecode checks. * src/eval.c (fetch_and_exec_byte_code, Ffetch_bytecode): Remove. (funcall_lambda): Call exec_byte_code directly, avoiding checks. * lisp/subr.el (fetch-bytecode): New definition, obsolete no-op. * lisp/emacs-lisp/disass.el (disassemble-1): * lisp/emacs-lisp/bytecomp.el (byte-compile-unfold-bcf): Remove calls to fetch-bytecode. (byte-compile-dynamic): Update doc string. (byte-compile-close-variables, byte-compile-from-buffer) (byte-compile-insert-header, byte-compile-output-file-form) (byte-compile--output-docform-recurse, byte-compile-output-docform) (byte-compile-file-form-defmumble): Remove effects of byte-compile-dynamic. * doc/lispref/compile.texi (Dynamic Loading): Remove node now that the entire `byte-compile-dynamic` facility has been rendered inert. * etc/NEWS: Announce changes.
Diffstat (limited to 'src')
-rw-r--r--src/bytecode.c27
-rw-r--r--src/eval.c59
-rw-r--r--src/lread.c49
3 files changed, 39 insertions, 96 deletions
diff --git a/src/bytecode.c b/src/bytecode.c
index ed6e2b34e77..def20b232c6 100644
--- a/src/bytecode.c
+++ b/src/bytecode.c
@@ -792,22 +792,19 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template,
792 Lisp_Object original_fun = call_fun; 792 Lisp_Object original_fun = call_fun;
793 if (SYMBOLP (call_fun)) 793 if (SYMBOLP (call_fun))
794 call_fun = XSYMBOL (call_fun)->u.s.function; 794 call_fun = XSYMBOL (call_fun)->u.s.function;
795 Lisp_Object template; 795 if (COMPILEDP (call_fun))
796 Lisp_Object bytecode;
797 if (COMPILEDP (call_fun)
798 /* Lexical binding only. */
799 && (template = AREF (call_fun, COMPILED_ARGLIST),
800 FIXNUMP (template))
801 /* No autoloads. */
802 && (bytecode = AREF (call_fun, COMPILED_BYTECODE),
803 !CONSP (bytecode)))
804 { 796 {
805 fun = call_fun; 797 Lisp_Object template = AREF (call_fun, COMPILED_ARGLIST);
806 bytestr = bytecode; 798 if (FIXNUMP (template))
807 args_template = XFIXNUM (template); 799 {
808 nargs = call_nargs; 800 /* Fast path for lexbound functions. */
809 args = call_args; 801 fun = call_fun;
810 goto setup_frame; 802 bytestr = AREF (call_fun, COMPILED_BYTECODE),
803 args_template = XFIXNUM (template);
804 nargs = call_nargs;
805 args = call_args;
806 goto setup_frame;
807 }
811 } 808 }
812 809
813 Lisp_Object val; 810 Lisp_Object val;
diff --git a/src/eval.c b/src/eval.c
index 6f1c39ffb0e..95eb21909d2 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -3122,19 +3122,6 @@ funcall_subr (struct Lisp_Subr *subr, ptrdiff_t numargs, Lisp_Object *args)
3122 xsignal2 (Qwrong_number_of_arguments, fun, make_fixnum (numargs)); 3122 xsignal2 (Qwrong_number_of_arguments, fun, make_fixnum (numargs));
3123} 3123}
3124 3124
3125/* Call the compiled Lisp function FUN. If we have not yet read FUN's
3126 bytecode string and constants vector, fetch them from the file first. */
3127
3128static Lisp_Object
3129fetch_and_exec_byte_code (Lisp_Object fun, ptrdiff_t args_template,
3130 ptrdiff_t nargs, Lisp_Object *args)
3131{
3132 if (CONSP (AREF (fun, COMPILED_BYTECODE)))
3133 Ffetch_bytecode (fun);
3134
3135 return exec_byte_code (fun, args_template, nargs, args);
3136}
3137
3138static Lisp_Object 3125static Lisp_Object
3139apply_lambda (Lisp_Object fun, Lisp_Object args, specpdl_ref count) 3126apply_lambda (Lisp_Object fun, Lisp_Object args, specpdl_ref count)
3140{ 3127{
@@ -3204,8 +3191,7 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
3204 ARGLIST slot value: pass the arguments to the byte-code 3191 ARGLIST slot value: pass the arguments to the byte-code
3205 engine directly. */ 3192 engine directly. */
3206 if (FIXNUMP (syms_left)) 3193 if (FIXNUMP (syms_left))
3207 return fetch_and_exec_byte_code (fun, XFIXNUM (syms_left), 3194 return exec_byte_code (fun, XFIXNUM (syms_left), nargs, arg_vector);
3208 nargs, arg_vector);
3209 /* Otherwise the bytecode object uses dynamic binding and the 3195 /* Otherwise the bytecode object uses dynamic binding and the
3210 ARGLIST slot contains a standard formal argument list whose 3196 ARGLIST slot contains a standard formal argument list whose
3211 variables are bound dynamically below. */ 3197 variables are bound dynamically below. */
@@ -3293,7 +3279,7 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
3293 val = XSUBR (fun)->function.a0 (); 3279 val = XSUBR (fun)->function.a0 ();
3294 } 3280 }
3295 else 3281 else
3296 val = fetch_and_exec_byte_code (fun, 0, 0, NULL); 3282 val = exec_byte_code (fun, 0, 0, NULL);
3297 3283
3298 return unbind_to (count, val); 3284 return unbind_to (count, val);
3299} 3285}
@@ -3411,46 +3397,6 @@ lambda_arity (Lisp_Object fun)
3411 return Fcons (make_fixnum (minargs), make_fixnum (maxargs)); 3397 return Fcons (make_fixnum (minargs), make_fixnum (maxargs));
3412} 3398}
3413 3399
3414DEFUN ("fetch-bytecode", Ffetch_bytecode, Sfetch_bytecode,
3415 1, 1, 0,
3416 doc: /* If byte-compiled OBJECT is lazy-loaded, fetch it now. */)
3417 (Lisp_Object object)
3418{
3419 Lisp_Object tem;
3420
3421 if (COMPILEDP (object))
3422 {
3423 if (CONSP (AREF (object, COMPILED_BYTECODE)))
3424 {
3425 tem = read_doc_string (AREF (object, COMPILED_BYTECODE));
3426 if (! (CONSP (tem) && STRINGP (XCAR (tem))
3427 && VECTORP (XCDR (tem))))
3428 {
3429 tem = AREF (object, COMPILED_BYTECODE);
3430 if (CONSP (tem) && STRINGP (XCAR (tem)))
3431 error ("Invalid byte code in %s", SDATA (XCAR (tem)));
3432 else
3433 error ("Invalid byte code");
3434 }
3435
3436 Lisp_Object bytecode = XCAR (tem);
3437 if (STRING_MULTIBYTE (bytecode))
3438 {
3439 /* BYTECODE must have been produced by Emacs 20.2 or earlier
3440 because it produced a raw 8-bit string for byte-code and now
3441 such a byte-code string is loaded as multibyte with raw 8-bit
3442 characters converted to multibyte form. Convert them back to
3443 the original unibyte form. */
3444 bytecode = Fstring_as_unibyte (bytecode);
3445 }
3446
3447 pin_string (bytecode);
3448 ASET (object, COMPILED_BYTECODE, bytecode);
3449 ASET (object, COMPILED_CONSTANTS, XCDR (tem));
3450 }
3451 }
3452 return object;
3453}
3454 3400
3455/* Return true if SYMBOL's default currently has a let-binding 3401/* Return true if SYMBOL's default currently has a let-binding
3456 which was made in the buffer that is now current. */ 3402 which was made in the buffer that is now current. */
@@ -4512,7 +4458,6 @@ alist of active lexical bindings. */);
4512 defsubr (&Srun_hook_with_args_until_success); 4458 defsubr (&Srun_hook_with_args_until_success);
4513 defsubr (&Srun_hook_with_args_until_failure); 4459 defsubr (&Srun_hook_with_args_until_failure);
4514 defsubr (&Srun_hook_wrapped); 4460 defsubr (&Srun_hook_wrapped);
4515 defsubr (&Sfetch_bytecode);
4516 defsubr (&Sbacktrace_debug); 4461 defsubr (&Sbacktrace_debug);
4517 DEFSYM (QCdebug_on_exit, ":debug-on-exit"); 4462 DEFSYM (QCdebug_on_exit, ":debug-on-exit");
4518 defsubr (&Smapbacktrace); 4463 defsubr (&Smapbacktrace);
diff --git a/src/lread.c b/src/lread.c
index 929f86ef283..e77bfb8021d 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -3481,6 +3481,8 @@ vector_from_rev_list (Lisp_Object elems)
3481 return obj; 3481 return obj;
3482} 3482}
3483 3483
3484static Lisp_Object get_lazy_string (Lisp_Object val);
3485
3484static Lisp_Object 3486static Lisp_Object
3485bytecode_from_rev_list (Lisp_Object elems, Lisp_Object readcharfun) 3487bytecode_from_rev_list (Lisp_Object elems, Lisp_Object readcharfun)
3486{ 3488{
@@ -3495,14 +3497,18 @@ bytecode_from_rev_list (Lisp_Object elems, Lisp_Object readcharfun)
3495 && FIXNATP (vec[COMPILED_STACK_DEPTH]))) 3497 && FIXNATP (vec[COMPILED_STACK_DEPTH])))
3496 invalid_syntax ("Invalid byte-code object", readcharfun); 3498 invalid_syntax ("Invalid byte-code object", readcharfun);
3497 3499
3498 if (load_force_doc_strings 3500 /* Always read 'lazily-loaded' bytecode (generated by the
3499 && NILP (vec[COMPILED_CONSTANTS]) 3501 `byte-compile-dynamic' feature prior to Emacs 30) eagerly, to
3500 && STRINGP (vec[COMPILED_BYTECODE])) 3502 avoid code in the fast path during execution. */
3503 if (CONSP (vec[COMPILED_BYTECODE]))
3504 vec[COMPILED_BYTECODE] = get_lazy_string (vec[COMPILED_BYTECODE]);
3505
3506 /* Lazily-loaded bytecode is represented by the constant slot being nil
3507 and the bytecode slot a (lazily loaded) string containing the
3508 print representation of (BYTECODE . CONSTANTS). Unpack the
3509 pieces by coerceing the string to unibyte and reading the result. */
3510 if (NILP (vec[COMPILED_CONSTANTS]))
3501 { 3511 {
3502 /* Lazily-loaded bytecode is represented by the constant slot being nil
3503 and the bytecode slot a (lazily loaded) string containing the
3504 print representation of (BYTECODE . CONSTANTS). Unpack the
3505 pieces by coerceing the string to unibyte and reading the result. */
3506 Lisp_Object enc = vec[COMPILED_BYTECODE]; 3512 Lisp_Object enc = vec[COMPILED_BYTECODE];
3507 Lisp_Object pair = Fread (Fcons (enc, readcharfun)); 3513 Lisp_Object pair = Fread (Fcons (enc, readcharfun));
3508 if (!CONSP (pair)) 3514 if (!CONSP (pair))
@@ -3512,25 +3518,20 @@ bytecode_from_rev_list (Lisp_Object elems, Lisp_Object readcharfun)
3512 vec[COMPILED_CONSTANTS] = XCDR (pair); 3518 vec[COMPILED_CONSTANTS] = XCDR (pair);
3513 } 3519 }
3514 3520
3515 if (!((STRINGP (vec[COMPILED_BYTECODE]) 3521 if (!(STRINGP (vec[COMPILED_BYTECODE])
3516 && VECTORP (vec[COMPILED_CONSTANTS])) 3522 && VECTORP (vec[COMPILED_CONSTANTS])))
3517 || CONSP (vec[COMPILED_BYTECODE])))
3518 invalid_syntax ("Invalid byte-code object", readcharfun); 3523 invalid_syntax ("Invalid byte-code object", readcharfun);
3519 3524
3520 if (STRINGP (vec[COMPILED_BYTECODE])) 3525 if (STRING_MULTIBYTE (vec[COMPILED_BYTECODE]))
3521 { 3526 /* BYTESTR must have been produced by Emacs 20.2 or earlier
3522 if (STRING_MULTIBYTE (vec[COMPILED_BYTECODE])) 3527 because it produced a raw 8-bit string for byte-code and
3523 { 3528 now such a byte-code string is loaded as multibyte with
3524 /* BYTESTR must have been produced by Emacs 20.2 or earlier 3529 raw 8-bit characters converted to multibyte form.
3525 because it produced a raw 8-bit string for byte-code and 3530 Convert them back to the original unibyte form. */
3526 now such a byte-code string is loaded as multibyte with 3531 vec[COMPILED_BYTECODE] = Fstring_as_unibyte (vec[COMPILED_BYTECODE]);
3527 raw 8-bit characters converted to multibyte form. 3532
3528 Convert them back to the original unibyte form. */ 3533 /* Bytecode must be immovable. */
3529 vec[COMPILED_BYTECODE] = Fstring_as_unibyte (vec[COMPILED_BYTECODE]); 3534 pin_string (vec[COMPILED_BYTECODE]);
3530 }
3531 /* Bytecode must be immovable. */
3532 pin_string (vec[COMPILED_BYTECODE]);
3533 }
3534 3535
3535 XSETPVECTYPE (XVECTOR (obj), PVEC_COMPILED); 3536 XSETPVECTYPE (XVECTOR (obj), PVEC_COMPILED);
3536 return obj; 3537 return obj;