diff options
Diffstat (limited to 'src/lread.c')
-rw-r--r-- | src/lread.c | 263 |
1 files changed, 218 insertions, 45 deletions
diff --git a/src/lread.c b/src/lread.c index 010194c34ea..a6c2db5d994 100644 --- a/src/lread.c +++ b/src/lread.c @@ -1119,7 +1119,7 @@ This uses the variables `load-suffixes' and `load-file-rep-suffixes'. */) } /* Return true if STRING ends with SUFFIX. */ -static bool +bool suffix_p (Lisp_Object string, const char *suffix) { ptrdiff_t suffix_len = strlen (suffix); @@ -1138,6 +1138,24 @@ close_infile_unwind (void *arg) infile = prev_infile; } +/* Compute the filename we want in `load-history' and `load-file-name'. */ + +static Lisp_Object +compute_found_effective (Lisp_Object found) +{ + /* Reconstruct the .elc filename. */ + Lisp_Object src_name = + Fgethash (Ffile_name_nondirectory (found), Vcomp_eln_to_el_h, Qnil); + + if (NILP (src_name)) + /* Manual eln load. */ + return found; + + if (suffix_p (src_name, "el.gz")) + src_name = Fsubstring (src_name, make_fixnum (0), make_fixnum (-3)); + return concat2 (src_name, build_string ("c")); +} + DEFUN ("load", Fload, Sload, 1, 5, 0, doc: /* Execute a file of Lisp code named FILE. First try FILE with `.elc' appended, then try with `.el', then try @@ -1222,6 +1240,8 @@ Return t if the file exists and loads successfully. */) else file = Fsubstitute_in_file_name (file); + bool no_native = suffix_p (file, ".elc"); + /* Avoid weird lossage with null string as arg, since it would try to load a directory as a Lisp file. */ if (SCHARS (file) == 0) @@ -1245,7 +1265,7 @@ Return t if the file exists and loads successfully. */) || suffix_p (file, MODULES_SECONDARY_SUFFIX) #endif #endif - ) + || (NATIVE_COMP_FLAG && suffix_p (file, NATIVE_ELISP_SUFFIX))) must_suffix = Qnil; /* Don't insist on adding a suffix if the argument includes a directory name. */ @@ -1262,7 +1282,9 @@ Return t if the file exists and loads successfully. */) suffixes = CALLN (Fappend, suffixes, Vload_file_rep_suffixes); } - fd = openp (Vload_path, file, suffixes, &found, Qnil, load_prefer_newer); + fd = + openp (Vload_path, file, suffixes, &found, Qnil, load_prefer_newer, + no_native); } if (fd == -1) @@ -1323,6 +1345,9 @@ Return t if the file exists and loads successfully. */) bool is_module = false; #endif + bool is_native_elisp = + NATIVE_COMP_FLAG && suffix_p (found, NATIVE_ELISP_SUFFIX) ? true : false; + /* Check if we're stuck in a recursive load cycle. 2000-09-21: It's not possible to just check for the file loaded @@ -1349,11 +1374,15 @@ Return t if the file exists and loads successfully. */) Vload_source_file_function. */ specbind (Qlexical_binding, Qnil); - /* Get the name for load-history. */ + Lisp_Object found_eff = + is_native_elisp + ? compute_found_effective (found) + : found; + hist_file_name = (! NILP (Vpurify_flag) ? concat2 (Ffile_name_directory (file), - Ffile_name_nondirectory (found)) - : found) ; + Ffile_name_nondirectory (found_eff)) + : found_eff); version = -1; @@ -1417,7 +1446,7 @@ Return t if the file exists and loads successfully. */) } /* !load_prefer_newer */ } } - else if (!is_module) + else if (!is_module && !is_native_elisp) { /* We are loading a source file (*.el). */ if (!NILP (Vload_source_file_function)) @@ -1444,7 +1473,7 @@ Return t if the file exists and loads successfully. */) stream = NULL; errno = EINVAL; } - else if (!is_module) + else if (!is_module && !is_native_elisp) { #ifdef WINDOWSNT emacs_close (fd); @@ -1460,7 +1489,7 @@ Return t if the file exists and loads successfully. */) might be accessed by the unbind_to call below. */ struct infile input; - if (is_module) + if (is_module || is_native_elisp) { /* `module-load' uses the file name, so we can close the stream now. */ @@ -1487,6 +1516,8 @@ Return t if the file exists and loads successfully. */) { if (is_module) message_with_string ("Loading %s (module)...", file, 1); + else if (is_native_elisp) + message_with_string ("Loading %s (native compiled elisp)...", file, 1); else if (!compiled) message_with_string ("Loading %s (source)...", file, 1); else if (newer) @@ -1496,7 +1527,8 @@ Return t if the file exists and loads successfully. */) message_with_string ("Loading %s...", file, 1); } - specbind (Qload_file_name, found); + specbind (Qload_file_name, found_eff); + specbind (Qload_true_file_name, found); specbind (Qinhibit_file_name_operation, Qnil); specbind (Qload_in_progress, Qt); @@ -1512,6 +1544,19 @@ Return t if the file exists and loads successfully. */) emacs_abort (); #endif } + else if (is_native_elisp) + { +#ifdef HAVE_NATIVE_COMP + specbind (Qcurrent_load_list, Qnil); + LOADHIST_ATTACH (hist_file_name); + Fnative_elisp_load (found, Qnil); + build_load_history (hist_file_name, true); +#else + /* This cannot happen. */ + emacs_abort (); +#endif + + } else { if (lisp_file_lexically_bound_p (Qget_file_char)) @@ -1547,6 +1592,8 @@ Return t if the file exists and loads successfully. */) { if (is_module) message_with_string ("Loading %s (module)...done", file, 1); + else if (is_native_elisp) + message_with_string ("Loading %s (native compiled elisp)...done", file, 1); else if (!compiled) message_with_string ("Loading %s (source)...done", file, 1); else if (newer) @@ -1592,12 +1639,109 @@ directories, make sure the PREDICATE function returns `dir-ok' for them. */) (Lisp_Object filename, Lisp_Object path, Lisp_Object suffixes, Lisp_Object predicate) { Lisp_Object file; - int fd = openp (path, filename, suffixes, &file, predicate, false); + int fd = openp (path, filename, suffixes, &file, predicate, false, false); if (NILP (predicate) && fd >= 0) emacs_close (fd); return file; } +#ifdef HAVE_NATIVE_COMP +static bool +maybe_swap_for_eln1 (Lisp_Object src_name, Lisp_Object eln_name, + Lisp_Object *filename, int *fd, struct timespec mtime) +{ + struct stat eln_st; + int eln_fd = emacs_open (SSDATA (ENCODE_FILE (eln_name)), O_RDONLY, 0); + + if (eln_fd > 0) + { + if (fstat (eln_fd, &eln_st) || S_ISDIR (eln_st.st_mode)) + emacs_close (eln_fd); + else + { + struct timespec eln_mtime = get_stat_mtime (&eln_st); + if (timespec_cmp (eln_mtime, mtime) >= 0) + { + emacs_close (*fd); + *fd = eln_fd; + *filename = eln_name; + /* Store the eln -> el relation. */ + Fputhash (Ffile_name_nondirectory (eln_name), + src_name, Vcomp_eln_to_el_h); + return true; + } + else + emacs_close (eln_fd); + } + } + + return false; +} +#endif + +/* Look for a suitable .eln file to be loaded in place of FILENAME. + If found replace the content of FILENAME and FD. */ + +static void +maybe_swap_for_eln (bool no_native, Lisp_Object *filename, int *fd, + struct timespec mtime) +{ +#ifdef HAVE_NATIVE_COMP + + if (no_native + || load_no_native) + Fputhash (*filename, Qt, V_comp_no_native_file_h); + else + Fremhash (*filename, V_comp_no_native_file_h); + + if (no_native + || load_no_native + || !suffix_p (*filename, ".elc")) + return; + + /* Search eln in the eln-cache directories. */ + Lisp_Object eln_path_tail = Vnative_comp_eln_load_path; + Lisp_Object src_name = + Fsubstring (*filename, Qnil, make_fixnum (-1)); + if (NILP (Ffile_exists_p (src_name))) + { + src_name = concat2 (src_name, build_string (".gz")); + if (NILP (Ffile_exists_p (src_name))) + { + if (!NILP (find_symbol_value ( + Qnative_comp_warning_on_missing_source))) + call2 (intern_c_string ("display-warning"), + Qcomp, + CALLN (Fformat, + build_string ("Cannot look-up eln file as no source " + "file was found for %s"), + *filename)); + return; + } + } + Lisp_Object eln_rel_name = Fcomp_el_to_eln_rel_filename (src_name); + + Lisp_Object dir = Qnil; + FOR_EACH_TAIL_SAFE (eln_path_tail) + { + dir = XCAR (eln_path_tail); + Lisp_Object eln_name = + Fexpand_file_name (eln_rel_name, + Fexpand_file_name (Vcomp_native_version_dir, dir)); + if (maybe_swap_for_eln1 (src_name, eln_name, filename, fd, mtime)) + return; + } + + /* Look also in preloaded subfolder of the last entry in + `comp-eln-load-path'. */ + dir = Fexpand_file_name (build_string ("preloaded"), + Fexpand_file_name (Vcomp_native_version_dir, + dir)); + maybe_swap_for_eln1 (src_name, Fexpand_file_name (eln_rel_name, dir), + filename, fd, mtime); +#endif +} + /* Search for a file whose name is STR, looking in directories in the Lisp list PATH, and trying suffixes from SUFFIX. On success, return a file descriptor (or 1 or -2 as described below). @@ -1622,11 +1766,14 @@ directories, make sure the PREDICATE function returns `dir-ok' for them. */) If NEWER is true, try all SUFFIXes and return the result for the newest file that exists. Does not apply to remote files, - or if a non-nil and non-t PREDICATE is specified. */ + or if a non-nil and non-t PREDICATE is specified. + + if NO_NATIVE is true do not try to load native code. */ int openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, - Lisp_Object *storeptr, Lisp_Object predicate, bool newer) + Lisp_Object *storeptr, Lisp_Object predicate, bool newer, + bool no_native) { ptrdiff_t fn_size = 100; char buf[100]; @@ -1798,7 +1945,17 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, } else { - fd = emacs_open (pfn, O_RDONLY, 0); + /* In some systems (like Windows) finding out if a + file exists is cheaper to do than actually opening + it. Only open the file when we are sure that it + exists. */ +#ifdef WINDOWSNT + if (faccessat (AT_FDCWD, pfn, R_OK, AT_EACCESS)) + fd = -1; + else +#endif + fd = emacs_open (pfn, O_RDONLY, 0); + if (fd < 0) { if (! (errno == ENOENT || errno == ENOTDIR)) @@ -1836,6 +1993,8 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, } else { + maybe_swap_for_eln (no_native, &string, &fd, + get_stat_mtime (&st)); /* We succeeded; return this descriptor and filename. */ if (storeptr) *storeptr = string; @@ -1847,6 +2006,8 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, /* No more suffixes. Return the newest. */ if (0 <= save_fd && ! CONSP (XCDR (tail))) { + maybe_swap_for_eln (no_native, &save_string, &save_fd, + save_mtime); if (storeptr) *storeptr = save_string; SAFE_FREE (); @@ -1942,8 +2103,8 @@ readevalloop_1 (int old) static AVOID end_of_file_error (void) { - if (STRINGP (Vload_file_name)) - xsignal1 (Qend_of_file, Vload_file_name); + if (STRINGP (Vload_true_file_name)) + xsignal1 (Qend_of_file, Vload_true_file_name); xsignal0 (Qend_of_file); } @@ -3777,8 +3938,7 @@ string_to_number (char const *string, int base, ptrdiff_t *plen) bool signedp = negative | positive; cp += signedp; - enum { INTOVERFLOW = 1, LEAD_INT = 2, DOT_CHAR = 4, TRAIL_INT = 8, - E_EXP = 16 }; + enum { INTOVERFLOW = 1, LEAD_INT = 2, TRAIL_INT = 4, E_EXP = 16 }; int state = 0; int leading_digit = digit_to_number (*cp, base); uintmax_t n = leading_digit; @@ -3798,7 +3958,6 @@ string_to_number (char const *string, int base, ptrdiff_t *plen) char const *after_digits = cp; if (*cp == '.') { - state |= DOT_CHAR; cp++; } @@ -3847,8 +4006,10 @@ string_to_number (char const *string, int base, ptrdiff_t *plen) cp = ecp; } - float_syntax = ((state & (DOT_CHAR|TRAIL_INT)) == (DOT_CHAR|TRAIL_INT) - || (state & ~INTOVERFLOW) == (LEAD_INT|E_EXP)); + /* A float has digits after the dot or an exponent. + This excludes numbers like "1." which are lexed as integers. */ + float_syntax = ((state & TRAIL_INT) + || ((state & LEAD_INT) && (state & E_EXP))); } if (plen) @@ -4204,10 +4365,14 @@ intern_c_string_1 (const char *str, ptrdiff_t len) if (!SYMBOLP (tem)) { - /* Creating a non-pure string from a string literal not implemented yet. - We could just use make_string here and live with the extra copy. */ - eassert (!NILP (Vpurify_flag)); - tem = intern_driver (make_pure_c_string (str, len), obarray, tem); + Lisp_Object string; + + if (NILP (Vpurify_flag)) + string = make_string (str, len); + else + string = make_pure_c_string (str, len); + + tem = intern_driver (string, obarray, tem); } return tem; } @@ -4467,6 +4632,10 @@ defsubr (union Aligned_Lisp_Subr *aname) XSETPVECTYPE (sname, PVEC_SUBR); XSETSUBR (tem, sname); set_symbol_function (sym, tem); +#ifdef HAVE_NATIVE_COMP + eassert (NILP (Vcomp_abi_hash)); + Vcomp_subr_list = Fpurecopy (Fcons (tem, Vcomp_subr_list)); +#endif } #ifdef NOTDEF /* Use fset in subr.el now! */ @@ -4600,14 +4769,8 @@ load_path_default (void) return decode_env_path (0, PATH_DUMPLOADSEARCH, 0); Lisp_Object lpath = Qnil; - const char *normal = PATH_LOADSEARCH; - const char *loadpath = NULL; -#ifdef HAVE_NS - loadpath = ns_load_path (); -#endif - - lpath = decode_env_path (0, loadpath ? loadpath : normal, 0); + lpath = decode_env_path (0, PATH_LOADSEARCH, 0); if (!NILP (Vinstallation_directory)) { @@ -4767,6 +4930,7 @@ init_lread (void) load_in_progress = 0; Vload_file_name = Qnil; + Vload_true_file_name = Qnil; Vstandard_input = Qt; Vloads_in_progress = Qnil; } @@ -4833,7 +4997,8 @@ to find all the symbols in an obarray, use `mapatoms'. */); DEFVAR_LISP ("values", Vvalues, doc: /* List of values of all expressions which were read, evaluated and printed. -Order is reverse chronological. */); +Order is reverse chronological. +This variable is obsolete as of Emacs 28.1 and should not be used. */); XSYMBOL (intern ("values"))->u.s.declared_special = false; DEFVAR_LISP ("standard-input", Vstandard_input, @@ -4890,20 +5055,15 @@ This list includes suffixes for both compiled and source Emacs Lisp files. This list should not include the empty string. `load' and related functions try to append these suffixes, in order, to the specified file name if a suffix is allowed or required. */); + Vload_suffixes = list2 (build_pure_c_string (".elc"), + build_pure_c_string (".el")); #ifdef HAVE_MODULES + Vload_suffixes = Fcons (build_pure_c_string (MODULES_SUFFIX), Vload_suffixes); #ifdef MODULES_SECONDARY_SUFFIX - Vload_suffixes = list4 (build_pure_c_string (".elc"), - build_pure_c_string (".el"), - build_pure_c_string (MODULES_SUFFIX), - build_pure_c_string (MODULES_SECONDARY_SUFFIX)); -#else - Vload_suffixes = list3 (build_pure_c_string (".elc"), - build_pure_c_string (".el"), - build_pure_c_string (MODULES_SUFFIX)); + Vload_suffixes = + Fcons (build_pure_c_string (MODULES_SECONDARY_SUFFIX), Vload_suffixes); #endif -#else - Vload_suffixes = list2 (build_pure_c_string (".elc"), - build_pure_c_string (".el")); + #endif DEFVAR_LISP ("module-file-suffix", Vmodule_file_suffix, doc: /* Suffix of loadable module file, or nil if modules are not supported. */); @@ -4970,9 +5130,17 @@ directory. These file names are converted to absolute at startup. */); Vload_history = Qnil; DEFVAR_LISP ("load-file-name", Vload_file_name, - doc: /* Full name of file being loaded by `load'. */); + doc: /* Full name of file being loaded by `load'. + +In case of native code being loaded this is indicating the +corresponding bytecode filename. Use `load-true-file-name' to obtain +the .eln filename. */); Vload_file_name = Qnil; + DEFVAR_LISP ("load-true-file-name", Vload_true_file_name, + doc: /* Full name of file being loaded by `load'. */); + Vload_true_file_name = Qnil; + DEFVAR_LISP ("user-init-file", Vuser_init_file, doc: /* File name, including directory, of user's initialization file. If the file loaded had extension `.elc', and the corresponding source file @@ -5092,6 +5260,10 @@ Note that if you customize this, obviously it will not affect files that are loaded before your customizations are read! */); load_prefer_newer = 0; + DEFVAR_BOOL ("load-no-native", load_no_native, + doc: /* Non-nil means not to load a .eln file when a .elc was requested. */); + load_no_native = false; + /* Vsource_directory was initialized in init_lread. */ DEFSYM (Qcurrent_load_list, "current-load-list"); @@ -5114,6 +5286,7 @@ that are loaded before your customizations are read! */); DEFSYM (Qfunction, "function"); DEFSYM (Qload, "load"); DEFSYM (Qload_file_name, "load-file-name"); + DEFSYM (Qload_true_file_name, "load-true-file-name"); DEFSYM (Qeval_buffer_list, "eval-buffer-list"); DEFSYM (Qdir_ok, "dir-ok"); DEFSYM (Qdo_after_load_evaluation, "do-after-load-evaluation"); |