diff options
| author | Mattias EngdegÄrd | 2024-01-30 17:55:19 +0100 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2024-01-31 17:12:25 +0100 |
| commit | 9bcc9690a8076a22398c27a7ccf836ee95eb16a2 (patch) | |
| tree | 8cc52b73bc6428f74da2c94c83990b01ce7032be /src | |
| parent | 7e85311a9113a4720ec9d7b06188646fc7bdae0b (diff) | |
| download | emacs-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.c | 27 | ||||
| -rw-r--r-- | src/eval.c | 59 | ||||
| -rw-r--r-- | src/lread.c | 49 |
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 | |||
| 3128 | static Lisp_Object | ||
| 3129 | fetch_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 | |||
| 3138 | static Lisp_Object | 3125 | static Lisp_Object |
| 3139 | apply_lambda (Lisp_Object fun, Lisp_Object args, specpdl_ref count) | 3126 | apply_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 | ||
| 3414 | DEFUN ("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 | ||
| 3484 | static Lisp_Object get_lazy_string (Lisp_Object val); | ||
| 3485 | |||
| 3484 | static Lisp_Object | 3486 | static Lisp_Object |
| 3485 | bytecode_from_rev_list (Lisp_Object elems, Lisp_Object readcharfun) | 3487 | bytecode_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; |