\f
-(defun comp-output-directory (src)
- "Return the compilation direcotry for source SRC."
- (let* ((src (if (symbolp src) (symbol-name src) src))
- (expanded-filename (expand-file-name src)))
- (file-name-as-directory
- (concat (file-name-directory expanded-filename)
- comp-native-path-postfix))))
-
-(defun comp-output-base-filename (src)
- "Output filename sans extention for SRC file being native compiled."
- (let* ((src (if (symbolp src) (symbol-name src) src))
- (expanded-filename (expand-file-name src))
- (output-dir (comp-output-directory src))
- (output-filename
- (file-name-sans-extension
- (file-name-nondirectory expanded-filename))))
- (expand-file-name output-filename output-dir)))
-
-(defun comp-output-filename (src)
- "Output filename for SRC file being native compiled."
- (concat (comp-output-base-filename src) ".eln"))
-
(defmacro comp-loop-insn-in-block (basic-block &rest body)
"Loop over all insns in BASIC-BLOCK executning BODY.
Inside BODY `insn' can be used to read or set the current
(unless (file-exists-p dir)
;; In case it's created in the meanwhile.
(ignore-error 'file-already-exists
- (make-directory dir)))
+ (make-directory dir t)))
(unless comp-dry-run
(comp--compile-ctxt-to-file name))))
source-file)
when (or comp-always-compile
(file-newer-than-file-p source-file
- (comp-output-filename source-file)))
+ (comp-el-to-eln-filename source-file)))
do (let* ((expr `(progn
(require 'comp)
(setf comp-speed ,comp-speed
(when (and load1
(zerop (process-exit-status process)))
(native-elisp-load
- (comp-output-filename source-file1)
+ (comp-el-to-eln-filename source-file1)
(eq load1 'late)))
(comp-run-async-workers)))))
(puthash source-file process comp-async-compilations))
(byte-compile-debug t)
(comp-ctxt
(make-comp-ctxt
- :output (comp-output-base-filename function-or-file)
+ :output (comp-el-to-eln-filename (if (symbolp function-or-file)
+ (symbol-name function-or-file)
+ function-or-file)
+ (when byte-native-for-bootstrap
+ (car (last comp-eln-load-path))))
:with-late-load with-late-load)))
(comp-log "\n\f\n" 1)
(condition-case err
(and (eq load 'late)
(cl-some (lambda (re) (string-match re file))
comp-deferred-compilation-black-list)))
- (let ((out-dir (comp-output-directory file))
- (out-filename (comp-output-filename file)))
+ (let* ((out-filename (comp-el-to-eln-filename file))
+ (out-dir (file-name-directory out-filename)))
(if (or (file-writable-p out-filename)
(and (not (file-exists-p out-dir))
(file-writable-p (substring out-dir 0 -1))))
((string-match "\\.el\\(c\\(\\..*\\)?\\)\\'" library)
(setq library (replace-match "" t t library)))
((string-match "\\.eln\\'" library)
- ;; From help-fns.el.
- (setq library (expand-file-name (concat (file-name-base library)
- ".el")
- (concat (file-name-directory library)
- "..")))))
+ (setq library (gethash (file-name-nondirectory library) comp-eln-to-el-h))))
(or
(locate-file library
(or find-function-source-path load-path)
(logior (if (memq 'executable predicate) 1 0)
(if (memq 'writable predicate) 2 0)
(if (memq 'readable predicate) 4 0))))
- (locate-file-internal filename path suffixes predicate))
+ (let ((file (locate-file-internal filename path suffixes predicate)))
+ (if (and file (string-match "\\.eln\\'" file))
+ (gethash (file-name-nondirectory file) comp-eln-to-el-h)
+ file)))
(defun locate-file-completion-table (dirs suffixes string pred action)
"Do completion for file names passed to `locate-file'."
object (or (if (symbolp type) type) 'defun))))
(file-name (if (and true-name
(string-match "[.]eln\\'" true-name))
- (expand-file-name (concat (file-name-base true-name)
- ".el")
- (concat (file-name-directory true-name)
- ".."))
+ (gethash (file-name-nondirectory true-name)
+ comp-eln-to-el-h)
true-name)))
(cond
(autoloaded
(setq user-emacs-directory
(startup--xdg-or-homedot startup--xdg-config-home-emacs nil))
+ (when (boundp 'comp-eln-load-path)
+ (setq comp-eln-load-path (cons (concat user-emacs-directory "eln-cache/")
+ comp-eln-load-path)))
;; Look in each dir in load-path for a subdirs.el file. If we
;; find one, load it, which will add the appropriate subdirs of
;; that dir into load-path. This needs to be done before setting
}
\f
+#define ELN_FILENAME_HASH_LEN 64
+
/* C symbols emitted for the load relocation mechanism. */
#define CURRENT_THREAD_RELOC_SYM "current_thread_reloc"
#define PURE_RELOC_SYM "pure_reloc"
return scratch_area;
}
+static Lisp_Object
+comp_hash_string (Lisp_Object string)
+{
+ Lisp_Object digest = make_uninit_string (SHA512_DIGEST_SIZE * 2);
+ sha512_buffer (SSDATA (string), SCHARS (string), SSDATA (digest));
+ hexbuf_digest (SSDATA (digest), SDATA (digest), SHA512_DIGEST_SIZE);
+
+ return digest;
+}
+
/* Produce a key hashing Vcomp_subr_list. */
void
{
Lisp_Object string = Fmapconcat (intern_c_string ("subr-name"),
Vcomp_subr_list, build_string (" "));
- Lisp_Object digest = make_uninit_string (SHA512_DIGEST_SIZE * 2);
-
- sha512_buffer (SSDATA (string), SCHARS (string), SSDATA (digest));
- hexbuf_digest (SSDATA (digest), SDATA (digest), SHA512_DIGEST_SIZE);
+ Lisp_Object digest = comp_hash_string (string);
/* Check runs once. */
eassert (NILP (Vcomp_abi_hash));
/* If 10 characters are usually sufficient for git I guess 16 are
fine for us here. */
Vcomp_native_path_postfix =
- concat3 (make_string ("eln-", 4),
- Vsystem_configuration,
+ concat2 (Vsystem_configuration,
concat2 (make_string ("-", 1),
Fsubstring_no_properties (Vcomp_abi_hash,
make_fixnum (0),
/* Entry points exposed to lisp. */
/**********************************/
+DEFUN ("comp-el-to-eln-filename", Fcomp_el_to_eln_filename,
+ Scomp_el_to_eln_filename, 1, 2, 0,
+ doc: /* Given a source file return the corresponding .eln true filename.
+If BASE-DIR is nil use the first entry in `comp-eln-load-path'. */)
+ (Lisp_Object file_name, Lisp_Object base_dir)
+{
+ CHECK_STRING (file_name);
+ file_name = Fexpand_file_name (file_name, Qnil);
+ Lisp_Object hashed = Fsubstring (comp_hash_string (file_name), Qnil,
+ make_fixnum (ELN_FILENAME_HASH_LEN));
+ file_name = concat2 (Ffile_name_nondirectory (Fsubstring (file_name, Qnil,
+ make_fixnum (-3))),
+ build_string ("-"));
+ file_name = concat3 (file_name, hashed, build_string (NATIVE_ELISP_SUFFIX));
+ if (NILP (base_dir))
+ base_dir = XCAR (Vcomp_eln_load_path);
+
+ if (!file_name_absolute_p (SSDATA (base_dir)))
+ base_dir = Fexpand_file_name (base_dir, Vinvocation_directory);
+
+ return Fexpand_file_name (file_name,
+ concat2 (base_dir, Vcomp_native_path_postfix));
+}
+
DEFUN ("comp--init-ctxt", Fcomp__init_ctxt, Scomp__init_ctxt,
0, 0, 0,
doc: /* Initialize the native compiler context. Return t on success. */)
Scomp__compile_ctxt_to_file,
1, 1, 0,
doc: /* Compile as native code the current context to file. */)
- (Lisp_Object base_name)
+ (Lisp_Object file_name)
{
load_gccjit_if_necessary (true);
- CHECK_STRING (base_name);
+ CHECK_STRING (file_name);
+ Lisp_Object base_name = Fsubstring (file_name, Qnil, make_fixnum (-4));
gcc_jit_context_set_int_option (comp.ctxt,
GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
AUTO_STRING (dot_so, NATIVE_ELISP_SUFFIX);
- Lisp_Object out_file = CALLN (Fconcat, base_name, dot_so);
Lisp_Object tmp_file =
Fmake_temp_file_internal (base_name, Qnil, dot_so, Qnil);
gcc_jit_context_compile_to_file (comp.ctxt,
GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY,
SSDATA (tmp_file));
- CALL2I (comp--replace-output-file, out_file, tmp_file);
+ CALL2I (comp--replace-output-file, file_name, tmp_file);
if (!noninteractive)
unbind_to (count, Qnil);
- return out_file;
+ return file_name;
}
DEFUN ("comp-libgccjit-version", Fcomp_libgccjit_version,
build_pure_c_string ("eln file inconsistent with current runtime "
"configuration, please recompile"));
+ defsubr (&Scomp_el_to_eln_filename);
defsubr (&Scomp__init_ctxt);
defsubr (&Scomp__release_ctxt);
defsubr (&Scomp__compile_ctxt_to_file);
internal use during */);
Vcomp_deferred_pending_h = CALLN (Fmake_hash_table, QCtest, Qeq);
+ DEFVAR_LISP ("comp-eln-to-el-h", Vcomp_eln_to_el_h,
+ doc: /* Hash table eln-filename -> el-filename. */);
+ Vcomp_eln_to_el_h = CALLN (Fmake_hash_table, QCtest, Qequal);
+
+ DEFVAR_LISP ("comp-eln-load-path", Vcomp_eln_load_path,
+ doc: /* List of eln cache directories.
+
+If a directory is non absolute is assumed to be relative to
+`invocation-directory'.
+The last directory of this list is assumed to be the system one. */);
+
+ /* Temporary value in use for boostrap. We can't do better as
+ `invocation-directory' is still unset, will be fixed up during
+ dump reload. */
+ Vcomp_eln_load_path = Fcons (build_string ("../eln-cache/"), Qnil);
+
#endif /* #ifdef HAVE_NATIVE_COMP */
defsubr (&Snative_comp_available_p);
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);
}
if (fd == -1)
same folder of their respective sources therfore not to break
packages we fake `load-file-name' here. The non faked
version of it is `load-true-file-name'. */
- specbind (Qload_file_name,
- concat2 (parent_directory (Ffile_name_directory (found)),
- Ffile_name_nondirectory (found)));
+ specbind (Qload_file_name, Fgethash (Ffile_name_nondirectory (found),
+ Vcomp_eln_to_el_h, Qnil));
}
else
specbind (Qload_file_name, found);
return file;
}
-/* This function turns a list of suffixes into a list of middle dirs
- and suffixes. If the suffix is not NATIVE_ELISP_SUFFIX then its
- suffix is nil and it is added to the list as is. Instead, if it
- suffix is NATIVE_ELISP_SUFFIX then two elements are added to the
- list. The first one has middledir equal to nil and the second uses
- comp-native-path-postfix as middledir. This is because we'd like
- to search for dir/foo.eln before dir/middledir/foo.eln.
+/* Look for a suitable .eln file to be loaded in place of FILENAME.
+ If found replace the content of FILENAME and FD. */
-For example, it turns this:
-
-(".eln" ".elc" ".elc.gz" ".el" ".el.gz")
-
- into this:
-
-((nil . ".eln")
- (comp-native-path-postfix . ".eln")
- (nil . ".elc")
- (nil . ".elc.gz")
- (nil . ".el")
- (nil . ".el.gz"))
-*/
-static Lisp_Object
-openp_add_middle_dir_to_suffixes (Lisp_Object suffixes)
+static void
+maybe_swap_for_eln (Lisp_Object *filename, int *fd, struct timespec mtime)
{
- Lisp_Object tail = suffixes;
- Lisp_Object extended_suf = Qnil;
- FOR_EACH_TAIL_SAFE (tail)
- {
- /* suffixes may be a stack-based cons pointing to stack-based
- strings. We must copy the suffix if we are putting it into
- a heap-based cons to avoid a dangling reference. This would
- lead to crashes during the GC. */
- CHECK_STRING_CAR (tail);
- char * suf = SSDATA (XCAR (tail));
- Lisp_Object copied_suffix = build_string (suf);
#ifdef HAVE_NATIVE_COMP
- if (strcmp (NATIVE_ELISP_SUFFIX, suf) == 0)
- {
- CHECK_STRING (Vcomp_native_path_postfix);
- /* Here we add them in the opposite order so that nreverse
- corrects it. */
- extended_suf = Fcons (Fcons (Qnil, copied_suffix), extended_suf);
- extended_suf = Fcons (Fcons (Vcomp_native_path_postfix,
- copied_suffix),
- extended_suf);
- }
- else
-#endif
- extended_suf = Fcons (Fcons (Qnil, copied_suffix), extended_suf);
- }
+ struct stat eln_st;
- suffixes = Fnreverse (extended_suf);
- return suffixes;
-}
+ if (!suffix_p (*filename, ".elc"))
+ return;
-/* This function takes a list of middledirs and suffixes and returns
- the maximum buffer space that this part of the filename will
- need. */
-static ptrdiff_t
-openp_max_middledir_and_suffix_len (Lisp_Object middledir_and_suffixes)
-{
- ptrdiff_t max_extra_len = 0;
- Lisp_Object tail = middledir_and_suffixes;
- FOR_EACH_TAIL_SAFE (tail)
+ /* Search eln in the eln-cache directories. */
+ Lisp_Object eln_path_tail = Vcomp_eln_load_path;
+ FOR_EACH_TAIL_SAFE (eln_path_tail)
{
- Lisp_Object middledir_and_suffix = XCAR (tail);
- Lisp_Object middledir = XCAR (middledir_and_suffix);
- Lisp_Object suffix = XCDR (middledir_and_suffix);
- ptrdiff_t len = SBYTES (suffix);
- if (!NILP (middledir))
- len += 2 + SBYTES (middledir); /* Add two slashes. */
- max_extra_len = max (max_extra_len, len);
- }
- return max_extra_len;
-}
+ Lisp_Object el_name =
+ Fsubstring (*filename, Qnil, make_fixnum (-1));
+ Lisp_Object eln_name =
+ Fcomp_el_to_eln_filename (el_name, XCAR (eln_path_tail));
+ int eln_fd = emacs_open (SSDATA (ENCODE_FILE (eln_name)), O_RDONLY, 0);
-/* This function completes the FN buffer with the middledir,
- basenameme, and suffix. It takes the directory length in DIRNAME,
- but it requires that it has been copied already to the start of
- the buffer.
-
- After this function the FN buffer will be (depending on middledir)
- dirname/middledir/basename.suffix
- or
- dirname/basename.suffix
-*/
-static ptrdiff_t
-openp_fill_filename_buffer (char *fn, ptrdiff_t dirnamelen,
- Lisp_Object basenamewext,
- Lisp_Object middledir_and_suffix)
-{
- Lisp_Object middledir = XCAR (middledir_and_suffix);
- Lisp_Object suffix = XCDR (middledir_and_suffix);
- ptrdiff_t basenamewext_len = SBYTES (basenamewext);
- ptrdiff_t fnlen, lsuffix = SBYTES (suffix);
- ptrdiff_t lmiddledir = 0;
- if (!NILP (middledir))
- {
- /* Add 1 for the slash. */
- lmiddledir = SBYTES (middledir) + 1;
- memcpy (fn + dirnamelen, SDATA (middledir),
- lmiddledir - 1);
- fn[dirnamelen + (lmiddledir - 1)] = '/';
+ 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)
+ {
+ *filename = eln_name;
+ emacs_close (*fd);
+ *fd = eln_fd;
+ /* Store the eln -> el relation. */
+ Fputhash (Ffile_name_nondirectory (eln_name),
+ el_name, Vcomp_eln_to_el_h);
+ return;
+ }
+ else
+ emacs_close (eln_fd);
+ }
+ }
}
-
- memcpy (fn + dirnamelen + lmiddledir, SDATA (basenamewext),
- basenamewext_len);
- /* Make complete filename by appending SUFFIX. */
- memcpy (fn + dirnamelen + lmiddledir + basenamewext_len,
- SDATA (suffix), lsuffix + 1);
- fnlen = dirnamelen + lmiddledir + basenamewext_len + lsuffix;
- return fnlen;
+#endif
}
/* Search for a file whose name is STR, looking in directories
ptrdiff_t want_length;
Lisp_Object filename;
Lisp_Object string, tail, encoded_fn, save_string;
- Lisp_Object middledir_and_suffixes;
- ptrdiff_t max_extra_len = 0;
+ ptrdiff_t max_suffix_len = 0;
int last_errno = ENOENT;
int save_fd = -1;
USE_SAFE_ALLOCA;
-
/* The last-modified time of the newest matching file found.
Initialize it to something less than all valid timestamps. */
struct timespec save_mtime = make_timespec (TYPE_MINIMUM (time_t), -1);
CHECK_STRING (str);
- middledir_and_suffixes = openp_add_middle_dir_to_suffixes (suffixes);
-
- max_extra_len = openp_max_middledir_and_suffix_len (middledir_and_suffixes);
+ tail = suffixes;
+ FOR_EACH_TAIL_SAFE (tail)
+ {
+ CHECK_STRING_CAR (tail);
+ max_suffix_len = max (max_suffix_len,
+ SBYTES (XCAR (tail)));
+ }
string = filename = encoded_fn = save_string = Qnil;
executable. */
FOR_EACH_TAIL_SAFE (path)
{
- ptrdiff_t dirnamelen, prefixlen;
+ ptrdiff_t baselen, prefixlen;
if (EQ (path, just_use_str))
filename = str;
continue;
}
-
/* Calculate maximum length of any filename made from
this path element/specified file name and any possible suffix. */
- want_length = max_extra_len + SBYTES (filename);
+ want_length = max_suffix_len + SBYTES (filename);
if (fn_size <= want_length)
{
fn_size = 100 + want_length;
fn = SAFE_ALLOCA (fn_size);
}
- Lisp_Object dirnamewslash = Ffile_name_directory (filename);
- Lisp_Object basenamewext = Ffile_name_nondirectory (filename);
-
/* Copy FILENAME's data to FN but remove starting /: if any. */
- prefixlen = ((SCHARS (dirnamewslash) > 2
- && SREF (dirnamewslash, 0) == '/'
- && SREF (dirnamewslash, 1) == ':')
+ prefixlen = ((SCHARS (filename) > 2
+ && SREF (filename, 0) == '/'
+ && SREF (filename, 1) == ':')
? 2 : 0);
- dirnamelen = SBYTES (dirnamewslash) - prefixlen;
- memcpy (fn, SDATA (dirnamewslash) + prefixlen, dirnamelen);
+ baselen = SBYTES (filename) - prefixlen;
+ memcpy (fn, SDATA (filename) + prefixlen, baselen);
- /* Loop over middledir_and_suffixes. */
- AUTO_LIST1 (empty_string_only, Fcons (Qnil, empty_unibyte_string));
- tail = NILP (middledir_and_suffixes) ? empty_string_only
- : middledir_and_suffixes;
+ /* Loop over suffixes. */
+ AUTO_LIST1 (empty_string_only, empty_unibyte_string);
+ tail = NILP (suffixes) ? empty_string_only : suffixes;
FOR_EACH_TAIL_SAFE (tail)
{
- Lisp_Object middledir_and_suffix = XCAR (tail);
- Lisp_Object suffix = XCDR (middledir_and_suffix);
+ Lisp_Object suffix = XCAR (tail);
+ ptrdiff_t fnlen, lsuffix = SBYTES (suffix);
Lisp_Object handler;
- ptrdiff_t fnlen = openp_fill_filename_buffer (fn, dirnamelen,
- basenamewext,
- middledir_and_suffix);
+ /* Make complete filename by appending SUFFIX. */
+ memcpy (fn + baselen, SDATA (suffix), lsuffix + 1);
+ fnlen = baselen + lsuffix;
/* Check that the file exists and is not a directory. */
/* We used to only check for handlers on non-absolute file names:
}
else
{
+ maybe_swap_for_eln (&string, &fd, get_stat_mtime (&st));
/* We succeeded; return this descriptor and filename. */
if (storeptr)
*storeptr = string;
+
SAFE_FREE ();
return fd;
}
/* No more suffixes. Return the newest. */
if (0 <= save_fd && ! CONSP (XCDR (tail)))
{
+ maybe_swap_for_eln (&save_string, &save_fd, save_mtime);
if (storeptr)
*storeptr = save_string;
SAFE_FREE ();
Vload_suffixes =
Fcons (build_pure_c_string (MODULES_SECONDARY_SUFFIX), Vload_suffixes);
#endif
-#endif
-#ifdef HAVE_NATIVE_COMP
- Vload_suffixes = Fcons (build_pure_c_string (NATIVE_ELISP_SUFFIX), Vload_suffixes);
-#endif
+#endif
DEFVAR_LISP ("module-file-suffix", Vmodule_file_suffix,
doc: /* Suffix of loadable module file, or nil if modules are not supported. */);
#ifdef HAVE_MODULES
{
fclose (file);
installation_state = INSTALLED;
+ /* FIXME Vcomp_eln_load_path = ?? */
}
else
- installation_state = LOCAL_BUILD;
+ {
+ installation_state = LOCAL_BUILD;
+ /* Fixup `comp-eln-load-path' so emacs can be invoked
+ position independently. */
+ Lisp_Object eln_cache_sys =
+ Ffile_name_directory (concat2 (Vinvocation_directory,
+ XCDR (comp_u->file)));
+ /* One directory up... */
+ eln_cache_sys =
+ Ffile_name_directory (Fsubstring (eln_cache_sys, Qnil,
+ make_fixnum (-1)));
+ /* FIXME for subsequent dumps we should fixup only the
+ last entry. */
+ Vcomp_eln_load_path = Fcons (eln_cache_sys, Qnil);
+ }
}
comp_u->file =