diff options
| author | Nicolás Bértolo | 2020-05-19 15:57:31 -0300 |
|---|---|---|
| committer | Andrea Corallo | 2020-05-25 09:42:10 +0100 |
| commit | 1b809f378f6263bc099da45c5e4a42c89fef8d71 (patch) | |
| tree | 1adfe55b6b0761de4f12bc0830aaab7a3296bc07 /src | |
| parent | 9daffe9cfe82d3b1e1e9fa8929dbb40cfed60f0f (diff) | |
| download | emacs-1b809f378f6263bc099da45c5e4a42c89fef8d71.tar.gz emacs-1b809f378f6263bc099da45c5e4a42c89fef8d71.zip | |
Improve handling of native compilation units still in use in Windows
When closing emacs will inspect all directories from which it loaded
native compilation units. If it finds a ".eln.old" file it will try to
delete it, if it fails that means that another Emacs instance is using it.
When compiling a file we rename the file that was in the output path
in case it has been loaded into another Emacs instance.
When deleting a package we move any ".eln" or ".eln.old" files in the
package folder that we can't delete to `package-user-dir`. Emacs will
check that directory when closing and delete them.
* lisp/emacs-lisp/comp.el (comp--replace-output-file): Function called
from C code to finish the compilation process. It performs renaming of
the old file if necessary.
* lisp/emacs-lisp/package.el (package--delete-directory): Function to
delete a package directory. It moves native compilation units that it
can't delete to `package-user-dir'.
* src/alloc.c (cleanup_vector): Call dispose_comp_unit().
(garbage_collect): Call finish_delayed_disposal_of_comp_units().
* src/comp.c: Restore the signal mask using unwind-protect. Store
loaded native compilation units in a hash table for disposal on
close. Store filenames of native compilation units GC'd in a linked
list to finish their disposal when the GC is over.
(clean_comp_unit_directory): Delete all *.eln.old files in a
directory.
(clean_package_user_dir_of_old_comp_units): Delete all *.eln.old files
in `package-user-dir'.
(dispose_all_remaining_comp_units): Dispose of native compilation
units that are still loaded.
(dispose_comp_unit): Close handle and cleanup directory or arrange for
later cleanup if DELAY is true.
(finish_delayed_disposal_of_comp_units): Dispose of native compilation
units that were GC'd.
(register_native_comp_unit): Register native compilation unit for
disposal when Emacs closes.
* src/comp.h: Introduce cfile member in Lisp_Native_Comp_Unit.
Add declarations of functions that: clean directories of unused native
compilation units, handle disposal of native compilation units.
* src/emacs.c (kill-emacs): Dispose all remaining compilation units
right right before calling exit().
* src/eval.c (internal_condition_case_3, internal_condition_case_4):
Add functions.
* src/lisp.h (internal_condition_case_3, internal_condition_case_4):
Add functions.
* src/pdumper.c (dump_do_dump_relocation): Set cfile to a copy of the
Lisp string specifying the file path.
Diffstat (limited to 'src')
| -rw-r--r-- | src/alloc.c | 3 | ||||
| -rw-r--r-- | src/comp.c | 260 | ||||
| -rw-r--r-- | src/comp.h | 34 | ||||
| -rw-r--r-- | src/emacs.c | 4 | ||||
| -rw-r--r-- | src/eval.c | 55 | ||||
| -rw-r--r-- | src/lisp.h | 2 | ||||
| -rw-r--r-- | src/pdumper.c | 3 |
7 files changed, 349 insertions, 12 deletions
diff --git a/src/alloc.c b/src/alloc.c index 76d49d2efd6..b892022125e 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -3119,8 +3119,7 @@ cleanup_vector (struct Lisp_Vector *vector) | |||
| 3119 | { | 3119 | { |
| 3120 | struct Lisp_Native_Comp_Unit *cu = | 3120 | struct Lisp_Native_Comp_Unit *cu = |
| 3121 | PSEUDOVEC_STRUCT (vector, Lisp_Native_Comp_Unit); | 3121 | PSEUDOVEC_STRUCT (vector, Lisp_Native_Comp_Unit); |
| 3122 | eassert (cu->handle); | 3122 | dispose_comp_unit (cu, true); |
| 3123 | dynlib_close (cu->handle); | ||
| 3124 | } | 3123 | } |
| 3125 | } | 3124 | } |
| 3126 | 3125 | ||
diff --git a/src/comp.c b/src/comp.c index 68ad6d3eb8d..16ad77c74bc 100644 --- a/src/comp.c +++ b/src/comp.c | |||
| @@ -411,6 +411,10 @@ load_gccjit_if_necessary (bool mandatory) | |||
| 411 | #define CALL1I(fun, arg) \ | 411 | #define CALL1I(fun, arg) \ |
| 412 | CALLN (Ffuncall, intern_c_string (STR (fun)), arg) | 412 | CALLN (Ffuncall, intern_c_string (STR (fun)), arg) |
| 413 | 413 | ||
| 414 | /* Like call2 but stringify and intern. */ | ||
| 415 | #define CALL2I(fun, arg1, arg2) \ | ||
| 416 | CALLN (Ffuncall, intern_c_string (STR (fun)), arg1, arg2) | ||
| 417 | |||
| 414 | #define DECL_BLOCK(name, func) \ | 418 | #define DECL_BLOCK(name, func) \ |
| 415 | gcc_jit_block *(name) = \ | 419 | gcc_jit_block *(name) = \ |
| 416 | gcc_jit_function_new_block ((func), STR (name)) | 420 | gcc_jit_function_new_block ((func), STR (name)) |
| @@ -435,6 +439,8 @@ typedef struct { | |||
| 435 | ptrdiff_t size; | 439 | ptrdiff_t size; |
| 436 | } f_reloc_t; | 440 | } f_reloc_t; |
| 437 | 441 | ||
| 442 | sigset_t saved_sigset; | ||
| 443 | |||
| 438 | static f_reloc_t freloc; | 444 | static f_reloc_t freloc; |
| 439 | 445 | ||
| 440 | /* C side of the compiler context. */ | 446 | /* C side of the compiler context. */ |
| @@ -3795,6 +3801,13 @@ DEFUN ("comp--release-ctxt", Fcomp__release_ctxt, Scomp__release_ctxt, | |||
| 3795 | return Qt; | 3801 | return Qt; |
| 3796 | } | 3802 | } |
| 3797 | 3803 | ||
| 3804 | static void | ||
| 3805 | restore_sigmask (void) | ||
| 3806 | { | ||
| 3807 | pthread_sigmask (SIG_SETMASK, &saved_sigset, 0); | ||
| 3808 | unblock_input (); | ||
| 3809 | } | ||
| 3810 | |||
| 3798 | DEFUN ("comp--compile-ctxt-to-file", Fcomp__compile_ctxt_to_file, | 3811 | DEFUN ("comp--compile-ctxt-to-file", Fcomp__compile_ctxt_to_file, |
| 3799 | Scomp__compile_ctxt_to_file, | 3812 | Scomp__compile_ctxt_to_file, |
| 3800 | 1, 1, 0, | 3813 | 1, 1, 0, |
| @@ -3816,6 +3829,8 @@ DEFUN ("comp--compile-ctxt-to-file", Fcomp__compile_ctxt_to_file, | |||
| 3816 | CALL1I (comp-data-container-idx, CALL1I (comp-ctxt-d-ephemeral, Vcomp_ctxt)); | 3829 | CALL1I (comp-data-container-idx, CALL1I (comp-ctxt-d-ephemeral, Vcomp_ctxt)); |
| 3817 | 3830 | ||
| 3818 | sigset_t oldset; | 3831 | sigset_t oldset; |
| 3832 | ptrdiff_t count = 0; | ||
| 3833 | |||
| 3819 | if (!noninteractive) | 3834 | if (!noninteractive) |
| 3820 | { | 3835 | { |
| 3821 | sigset_t blocked; | 3836 | sigset_t blocked; |
| @@ -3828,6 +3843,8 @@ DEFUN ("comp--compile-ctxt-to-file", Fcomp__compile_ctxt_to_file, | |||
| 3828 | sigaddset (&blocked, SIGIO); | 3843 | sigaddset (&blocked, SIGIO); |
| 3829 | #endif | 3844 | #endif |
| 3830 | pthread_sigmask (SIG_BLOCK, &blocked, &oldset); | 3845 | pthread_sigmask (SIG_BLOCK, &blocked, &oldset); |
| 3846 | count = SPECPDL_INDEX (); | ||
| 3847 | record_unwind_protect_void (restore_sigmask); | ||
| 3831 | } | 3848 | } |
| 3832 | emit_ctxt_code (); | 3849 | emit_ctxt_code (); |
| 3833 | 3850 | ||
| @@ -3866,18 +3883,10 @@ DEFUN ("comp--compile-ctxt-to-file", Fcomp__compile_ctxt_to_file, | |||
| 3866 | GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY, | 3883 | GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY, |
| 3867 | SSDATA (tmp_file)); | 3884 | SSDATA (tmp_file)); |
| 3868 | 3885 | ||
| 3869 | /* Remove the old eln instead of copying the new one into it to get | 3886 | CALL2I(comp--replace-output-file, out_file, tmp_file); |
| 3870 | a new inode and prevent crashes in case the old one is currently | ||
| 3871 | loaded. */ | ||
| 3872 | if (!NILP (Ffile_exists_p (out_file))) | ||
| 3873 | Fdelete_file (out_file, Qnil); | ||
| 3874 | Frename_file (tmp_file, out_file, Qnil); | ||
| 3875 | 3887 | ||
| 3876 | if (!noninteractive) | 3888 | if (!noninteractive) |
| 3877 | { | 3889 | unbind_to (count, Qnil); |
| 3878 | pthread_sigmask (SIG_SETMASK, &oldset, 0); | ||
| 3879 | unblock_input (); | ||
| 3880 | } | ||
| 3881 | 3890 | ||
| 3882 | return out_file; | 3891 | return out_file; |
| 3883 | } | 3892 | } |
| @@ -3939,6 +3948,223 @@ helper_PSEUDOVECTOR_TYPEP_XUNTAG (Lisp_Object a, enum pvec_type code) | |||
| 3939 | } | 3948 | } |
| 3940 | 3949 | ||
| 3941 | 3950 | ||
| 3951 | /*********************************/ | ||
| 3952 | /* Disposal of compilation units */ | ||
| 3953 | /*********************************/ | ||
| 3954 | |||
| 3955 | /* | ||
| 3956 | The problem: Windows does not let us delete an .eln file that has been | ||
| 3957 | loaded by a process. This has two implications in Emacs: | ||
| 3958 | |||
| 3959 | 1) It is not possible to recompile a lisp file if the corresponding | ||
| 3960 | .eln file has been loaded. This is because we'd like to use the same | ||
| 3961 | filename, but we can't delete the old .eln file. | ||
| 3962 | |||
| 3963 | 2) It is not possible to delete a package using `package-delete' | ||
| 3964 | if an .eln file has been loaded. | ||
| 3965 | |||
| 3966 | * General idea | ||
| 3967 | |||
| 3968 | The solution to these two problems is to move the foo.eln file | ||
| 3969 | somewhere else and have the last Emacs instance using it delete it. | ||
| 3970 | To make it easy to find what files need to be removed we use two approaches. | ||
| 3971 | |||
| 3972 | In the 1) case we rename foo.eln to fooXXXXXX.eln.old in the same | ||
| 3973 | folder. When Emacs is unloading "foo" (either GC'd the native | ||
| 3974 | compilation unit or Emacs is closing (see below)) we delete all the | ||
| 3975 | .eln.old files in the folder where the original foo.eln was stored. | ||
| 3976 | |||
| 3977 | Ideally we'd figure out the new name of foo.eln and delete it if | ||
| 3978 | it ends in .eln.old. There is no simple API to do this in | ||
| 3979 | Windows. GetModuleFileName() returns the original filename, not the | ||
| 3980 | current one. This forces us to put .eln.old files in an agreed upon | ||
| 3981 | path. We cannot use %TEMP% because it may be in another drive and then | ||
| 3982 | the rename operation would fail. | ||
| 3983 | |||
| 3984 | In the 2) case we can't use the same folder where the .eln file | ||
| 3985 | resided, as we are trying to completely remove the package. Since we | ||
| 3986 | are removing packages we can safely move the .eln.old file to | ||
| 3987 | `package-user-dir' as we are sure that that would not mean changing | ||
| 3988 | drives. | ||
| 3989 | |||
| 3990 | * Implementation details | ||
| 3991 | |||
| 3992 | The concept of disposal of a native compilation unit refers to | ||
| 3993 | unloading the shared library and deleting all the .eln.old files in | ||
| 3994 | the directory. These are two separate steps. We'll call them | ||
| 3995 | early-disposal and late-disposal. | ||
| 3996 | |||
| 3997 | There are two data structures used: | ||
| 3998 | |||
| 3999 | - The `all_loaded_comp_units_h` hashtable. | ||
| 4000 | |||
| 4001 | This hashtable is used like an array of weak references to native | ||
| 4002 | compilation units. This hash table is filled by load_comp_unit() and | ||
| 4003 | dispose_all_remaining_comp_units() iterates over all values that were | ||
| 4004 | not disposed by the GC and performs all disposal steps when Emacs is | ||
| 4005 | closing. | ||
| 4006 | |||
| 4007 | - The `delayed_comp_unit_disposal_list` list. | ||
| 4008 | |||
| 4009 | This is were the dispose_comp_unit() function, when called by the GC | ||
| 4010 | sweep stage, stores the original filenames of the disposed native | ||
| 4011 | compilation units. This is an ad-hoc C structure instead of a Lisp | ||
| 4012 | cons because we need to allocate instances of this structure during | ||
| 4013 | the GC. | ||
| 4014 | |||
| 4015 | The finish_delayed_disposal_of_comp_units() function will iterate over | ||
| 4016 | this list and perform the late-disposal step when Emacs is closing. | ||
| 4017 | |||
| 4018 | */ | ||
| 4019 | |||
| 4020 | #ifdef WINDOWSNT | ||
| 4021 | #define OLD_ELN_SUFFIX_REGEXP build_string ("\\.eln\\.old\\'") | ||
| 4022 | |||
| 4023 | static Lisp_Object all_loaded_comp_units_h; | ||
| 4024 | |||
| 4025 | /* We need to allocate instances of this struct during a GC | ||
| 4026 | * sweep. This is why it can't be transformed into a simple cons. | ||
| 4027 | */ | ||
| 4028 | struct delayed_comp_unit_disposal | ||
| 4029 | { | ||
| 4030 | struct delayed_comp_unit_disposal *next; | ||
| 4031 | char *filename; | ||
| 4032 | }; | ||
| 4033 | |||
| 4034 | struct delayed_comp_unit_disposal *delayed_comp_unit_disposal_list; | ||
| 4035 | |||
| 4036 | static Lisp_Object | ||
| 4037 | return_nil (Lisp_Object arg) | ||
| 4038 | { | ||
| 4039 | return Qnil; | ||
| 4040 | } | ||
| 4041 | |||
| 4042 | /* Tries to remove all *.eln.old files in DIRNAME. | ||
| 4043 | |||
| 4044 | * Any error is ignored because it may be due to the file being loaded | ||
| 4045 | * in another Emacs instance. | ||
| 4046 | */ | ||
| 4047 | static void | ||
| 4048 | clean_comp_unit_directory (Lisp_Object dirpath) | ||
| 4049 | { | ||
| 4050 | if (NILP (dirpath)) | ||
| 4051 | return; | ||
| 4052 | Lisp_Object files_in_dir; | ||
| 4053 | files_in_dir = internal_condition_case_4 (Fdirectory_files, dirpath, Qt, | ||
| 4054 | OLD_ELN_SUFFIX_REGEXP, Qnil, Qt, | ||
| 4055 | return_nil); | ||
| 4056 | FOR_EACH_TAIL (files_in_dir) { DeleteFile (SSDATA (XCAR (files_in_dir))); } | ||
| 4057 | } | ||
| 4058 | |||
| 4059 | /* Tries to remove all *.eln.old files in `package-user-dir'. | ||
| 4060 | |||
| 4061 | * This is called when Emacs is closing to clean any *.eln left from a | ||
| 4062 | * deleted package. | ||
| 4063 | */ | ||
| 4064 | void | ||
| 4065 | clean_package_user_dir_of_old_comp_units (void) | ||
| 4066 | { | ||
| 4067 | Lisp_Object package_user_dir | ||
| 4068 | = find_symbol_value (intern ("package-user-dir")); | ||
| 4069 | if (EQ (package_user_dir, Qunbound) || !STRINGP (package_user_dir)) | ||
| 4070 | return; | ||
| 4071 | |||
| 4072 | clean_comp_unit_directory (package_user_dir); | ||
| 4073 | } | ||
| 4074 | |||
| 4075 | /* This function disposes all compilation units that are still loaded. | ||
| 4076 | * It is important that this function is called only right before | ||
| 4077 | * Emacs is closed, otherwise we risk running a subr that is | ||
| 4078 | * implemented in an unloaded dynamic library. | ||
| 4079 | */ | ||
| 4080 | void | ||
| 4081 | dispose_all_remaining_comp_units (void) | ||
| 4082 | { | ||
| 4083 | struct Lisp_Hash_Table *h = XHASH_TABLE (all_loaded_comp_units_h); | ||
| 4084 | |||
| 4085 | for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i) | ||
| 4086 | { | ||
| 4087 | Lisp_Object k = HASH_KEY (h, i); | ||
| 4088 | if (!EQ (k, Qunbound)) | ||
| 4089 | { | ||
| 4090 | Lisp_Object val = HASH_VALUE (h, i); | ||
| 4091 | struct Lisp_Native_Comp_Unit *cu = XNATIVE_COMP_UNIT (val); | ||
| 4092 | dispose_comp_unit (cu, false); | ||
| 4093 | } | ||
| 4094 | } | ||
| 4095 | } | ||
| 4096 | |||
| 4097 | /* This function finishes the disposal of compilation units that were | ||
| 4098 | * passed to `dispose_comp_unit` with DELAY == true. | ||
| 4099 | * | ||
| 4100 | * This function is called when Emacs is idle and when it is about to | ||
| 4101 | * close. | ||
| 4102 | */ | ||
| 4103 | void | ||
| 4104 | finish_delayed_disposal_of_comp_units (void) | ||
| 4105 | { | ||
| 4106 | for (struct delayed_comp_unit_disposal *item | ||
| 4107 | = delayed_comp_unit_disposal_list; | ||
| 4108 | delayed_comp_unit_disposal_list; item = delayed_comp_unit_disposal_list) | ||
| 4109 | { | ||
| 4110 | delayed_comp_unit_disposal_list = item->next; | ||
| 4111 | Lisp_Object dirname = internal_condition_case_1 ( | ||
| 4112 | Ffile_name_directory, build_string (item->filename), Qt, return_nil); | ||
| 4113 | clean_comp_unit_directory (dirname); | ||
| 4114 | xfree (item->filename); | ||
| 4115 | xfree (item); | ||
| 4116 | } | ||
| 4117 | } | ||
| 4118 | #endif | ||
| 4119 | |||
| 4120 | /* This function puts the compilation unit in the | ||
| 4121 | * `all_loaded_comp_units_h` hashmap. | ||
| 4122 | */ | ||
| 4123 | static void | ||
| 4124 | register_native_comp_unit (Lisp_Object comp_u) | ||
| 4125 | { | ||
| 4126 | #ifdef WINDOWSNT | ||
| 4127 | Fputhash (CALL1I (gensym, Qnil), comp_u, all_loaded_comp_units_h); | ||
| 4128 | #endif | ||
| 4129 | } | ||
| 4130 | |||
| 4131 | /* This function disposes compilation units. It is called during the GC sweep | ||
| 4132 | * stage and when Emacs is closing. | ||
| 4133 | |||
| 4134 | * On Windows the the DELAY parameter specifies whether the native | ||
| 4135 | * compilation file will be deleted right away (if necessary) or put | ||
| 4136 | * on a list. That list will be dealt with by | ||
| 4137 | * `finish_delayed_disposal_of_comp_units`. | ||
| 4138 | */ | ||
| 4139 | void | ||
| 4140 | dispose_comp_unit (struct Lisp_Native_Comp_Unit *comp_handle, bool delay) | ||
| 4141 | { | ||
| 4142 | eassert (comp_handle->handle); | ||
| 4143 | dynlib_close (comp_handle->handle); | ||
| 4144 | #ifdef WINDOWSNT | ||
| 4145 | if (!delay) | ||
| 4146 | { | ||
| 4147 | Lisp_Object dirname = internal_condition_case_1 ( | ||
| 4148 | Ffile_name_directory, build_string (comp_handle->cfile), Qt, | ||
| 4149 | return_nil); | ||
| 4150 | if (!NILP (dirname)) | ||
| 4151 | clean_comp_unit_directory (dirname); | ||
| 4152 | xfree (comp_handle->cfile); | ||
| 4153 | comp_handle->cfile = NULL; | ||
| 4154 | } | ||
| 4155 | else | ||
| 4156 | { | ||
| 4157 | struct delayed_comp_unit_disposal *head; | ||
| 4158 | head = xmalloc (sizeof (struct delayed_comp_unit_disposal)); | ||
| 4159 | head->next = delayed_comp_unit_disposal_list; | ||
| 4160 | head->filename = comp_handle->cfile; | ||
| 4161 | comp_handle->cfile = NULL; | ||
| 4162 | delayed_comp_unit_disposal_list = head; | ||
| 4163 | } | ||
| 4164 | #endif | ||
| 4165 | } | ||
| 4166 | |||
| 4167 | |||
| 3942 | /***********************************/ | 4168 | /***********************************/ |
| 3943 | /* Deferred compilation mechanism. */ | 4169 | /* Deferred compilation mechanism. */ |
| 3944 | /***********************************/ | 4170 | /***********************************/ |
| @@ -4159,6 +4385,12 @@ load_comp_unit (struct Lisp_Native_Comp_Unit *comp_u, bool loading_dump, | |||
| 4159 | d_vec_len = XFIXNUM (Flength (comp_u->data_impure_vec)); | 4385 | d_vec_len = XFIXNUM (Flength (comp_u->data_impure_vec)); |
| 4160 | for (EMACS_INT i = 0; i < d_vec_len; i++) | 4386 | for (EMACS_INT i = 0; i < d_vec_len; i++) |
| 4161 | data_imp_relocs[i] = AREF (comp_u->data_impure_vec, i); | 4387 | data_imp_relocs[i] = AREF (comp_u->data_impure_vec, i); |
| 4388 | |||
| 4389 | /* If we register them while dumping we will get some entries in | ||
| 4390 | the hash table that will be duplicated when pdumper calls | ||
| 4391 | load_comp_unit. */ | ||
| 4392 | if (!will_dump_p ()) | ||
| 4393 | register_native_comp_unit (comp_u_lisp_obj); | ||
| 4162 | } | 4394 | } |
| 4163 | 4395 | ||
| 4164 | if (!loading_dump) | 4396 | if (!loading_dump) |
| @@ -4316,6 +4548,9 @@ DEFUN ("native-elisp-load", Fnative_elisp_load, Snative_elisp_load, 1, 2, 0, | |||
| 4316 | if (!comp_u->handle) | 4548 | if (!comp_u->handle) |
| 4317 | xsignal2 (Qnative_lisp_load_failed, file, build_string (dynlib_error ())); | 4549 | xsignal2 (Qnative_lisp_load_failed, file, build_string (dynlib_error ())); |
| 4318 | comp_u->file = file; | 4550 | comp_u->file = file; |
| 4551 | #ifdef WINDOWSNT | ||
| 4552 | comp_u->cfile = xlispstrdup (file); | ||
| 4553 | #endif | ||
| 4319 | comp_u->data_vec = Qnil; | 4554 | comp_u->data_vec = Qnil; |
| 4320 | comp_u->lambda_gc_guard = CALLN (Fmake_hash_table, QCtest, Qeq); | 4555 | comp_u->lambda_gc_guard = CALLN (Fmake_hash_table, QCtest, Qeq); |
| 4321 | comp_u->lambda_c_name_idx_h = CALLN (Fmake_hash_table, QCtest, Qequal); | 4556 | comp_u->lambda_c_name_idx_h = CALLN (Fmake_hash_table, QCtest, Qequal); |
| @@ -4464,6 +4699,11 @@ syms_of_comp (void) | |||
| 4464 | staticpro (&delayed_sources); | 4699 | staticpro (&delayed_sources); |
| 4465 | delayed_sources = Qnil; | 4700 | delayed_sources = Qnil; |
| 4466 | 4701 | ||
| 4702 | #ifdef WINDOWSNT | ||
| 4703 | staticpro (&all_loaded_comp_units_h); | ||
| 4704 | all_loaded_comp_units_h = CALLN(Fmake_hash_table, QCweakness, Qvalue); | ||
| 4705 | #endif | ||
| 4706 | |||
| 4467 | DEFVAR_LISP ("comp-ctxt", Vcomp_ctxt, | 4707 | DEFVAR_LISP ("comp-ctxt", Vcomp_ctxt, |
| 4468 | doc: /* The compiler context. */); | 4708 | doc: /* The compiler context. */); |
| 4469 | Vcomp_ctxt = Qnil; | 4709 | Vcomp_ctxt = Qnil; |
diff --git a/src/comp.h b/src/comp.h index 36e7cdf4413..b8e40ceb900 100644 --- a/src/comp.h +++ b/src/comp.h | |||
| @@ -52,7 +52,15 @@ struct Lisp_Native_Comp_Unit | |||
| 52 | /* STUFFS WE DO NOT DUMP!! */ | 52 | /* STUFFS WE DO NOT DUMP!! */ |
| 53 | Lisp_Object *data_imp_relocs; | 53 | Lisp_Object *data_imp_relocs; |
| 54 | bool loaded_once; | 54 | bool loaded_once; |
| 55 | |||
| 55 | dynlib_handle_ptr handle; | 56 | dynlib_handle_ptr handle; |
| 57 | #ifdef WINDOWSNT | ||
| 58 | /* We need to store a copy of the original file name in memory that | ||
| 59 | is not subject to GC because the function to dispose native | ||
| 60 | compilation units is called by the GC. By that time the `file' | ||
| 61 | string may have been sweeped. */ | ||
| 62 | char * cfile; | ||
| 63 | #endif | ||
| 56 | }; | 64 | }; |
| 57 | 65 | ||
| 58 | #ifdef HAVE_NATIVE_COMP | 66 | #ifdef HAVE_NATIVE_COMP |
| @@ -83,6 +91,14 @@ extern void syms_of_comp (void); | |||
| 83 | 91 | ||
| 84 | extern void maybe_defer_native_compilation (Lisp_Object function_name, | 92 | extern void maybe_defer_native_compilation (Lisp_Object function_name, |
| 85 | Lisp_Object definition); | 93 | Lisp_Object definition); |
| 94 | |||
| 95 | extern void dispose_comp_unit (struct Lisp_Native_Comp_Unit * comp_unit, bool delay); | ||
| 96 | |||
| 97 | extern void finish_delayed_disposal_of_comp_units (void); | ||
| 98 | |||
| 99 | extern void dispose_all_remaining_comp_units (void); | ||
| 100 | |||
| 101 | extern void clean_package_user_dir_of_old_comp_units (void); | ||
| 86 | #else | 102 | #else |
| 87 | 103 | ||
| 88 | static inline void | 104 | static inline void |
| @@ -92,6 +108,24 @@ maybe_defer_native_compilation (Lisp_Object function_name, | |||
| 92 | 108 | ||
| 93 | extern void syms_of_comp (void); | 109 | extern void syms_of_comp (void); |
| 94 | 110 | ||
| 111 | static inline void | ||
| 112 | dispose_comp_unit (struct Lisp_Native_Comp_Unit * comp_handle) | ||
| 113 | { | ||
| 114 | eassert (false); | ||
| 115 | } | ||
| 116 | |||
| 117 | static inline void | ||
| 118 | dispose_all_remaining_comp_units (void) | ||
| 119 | {} | ||
| 120 | |||
| 121 | static inline void | ||
| 122 | clean_package_user_dir_of_old_comp_units (void) | ||
| 123 | {} | ||
| 124 | |||
| 125 | static inline void | ||
| 126 | finish_delayed_disposal_of_comp_units (void) | ||
| 127 | {} | ||
| 128 | |||
| 95 | #endif | 129 | #endif |
| 96 | 130 | ||
| 97 | #endif | 131 | #endif |
diff --git a/src/emacs.c b/src/emacs.c index 93a837a44ef..2a7a5257f15 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -2398,6 +2398,10 @@ all of which are called before Emacs is actually killed. */ | |||
| 2398 | unlink (SSDATA (listfile)); | 2398 | unlink (SSDATA (listfile)); |
| 2399 | } | 2399 | } |
| 2400 | 2400 | ||
| 2401 | finish_delayed_disposal_of_comp_units (); | ||
| 2402 | dispose_all_remaining_comp_units (); | ||
| 2403 | clean_package_user_dir_of_old_comp_units (); | ||
| 2404 | |||
| 2401 | if (FIXNUMP (arg)) | 2405 | if (FIXNUMP (arg)) |
| 2402 | exit_code = (XFIXNUM (arg) < 0 | 2406 | exit_code = (XFIXNUM (arg) < 0 |
| 2403 | ? XFIXNUM (arg) | INT_MIN | 2407 | ? XFIXNUM (arg) | INT_MIN |
diff --git a/src/eval.c b/src/eval.c index 37d466f69ed..9e86a185908 100644 --- a/src/eval.c +++ b/src/eval.c | |||
| @@ -1419,6 +1419,61 @@ internal_condition_case_2 (Lisp_Object (*bfun) (Lisp_Object, Lisp_Object), | |||
| 1419 | } | 1419 | } |
| 1420 | } | 1420 | } |
| 1421 | 1421 | ||
| 1422 | /* Like internal_condition_case_1 but call BFUN with ARG1, ARG2, ARG3 as | ||
| 1423 | its arguments. */ | ||
| 1424 | |||
| 1425 | Lisp_Object | ||
| 1426 | internal_condition_case_3 (Lisp_Object (*bfun) (Lisp_Object, Lisp_Object, | ||
| 1427 | Lisp_Object), | ||
| 1428 | Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3, | ||
| 1429 | Lisp_Object handlers, | ||
| 1430 | Lisp_Object (*hfun) (Lisp_Object)) | ||
| 1431 | { | ||
| 1432 | struct handler *c = push_handler (handlers, CONDITION_CASE); | ||
| 1433 | if (sys_setjmp (c->jmp)) | ||
| 1434 | { | ||
| 1435 | Lisp_Object val = handlerlist->val; | ||
| 1436 | clobbered_eassert (handlerlist == c); | ||
| 1437 | handlerlist = handlerlist->next; | ||
| 1438 | return hfun (val); | ||
| 1439 | } | ||
| 1440 | else | ||
| 1441 | { | ||
| 1442 | Lisp_Object val = bfun (arg1, arg2, arg3); | ||
| 1443 | eassert (handlerlist == c); | ||
| 1444 | handlerlist = c->next; | ||
| 1445 | return val; | ||
| 1446 | } | ||
| 1447 | } | ||
| 1448 | |||
| 1449 | /* Like internal_condition_case_1 but call BFUN with ARG1, ARG2, ARG3, ARG4 as | ||
| 1450 | its arguments. */ | ||
| 1451 | |||
| 1452 | Lisp_Object | ||
| 1453 | internal_condition_case_4 (Lisp_Object (*bfun) (Lisp_Object, Lisp_Object, | ||
| 1454 | Lisp_Object, Lisp_Object), | ||
| 1455 | Lisp_Object arg1, Lisp_Object arg2, | ||
| 1456 | Lisp_Object arg3, Lisp_Object arg4, | ||
| 1457 | Lisp_Object handlers, | ||
| 1458 | Lisp_Object (*hfun) (Lisp_Object)) | ||
| 1459 | { | ||
| 1460 | struct handler *c = push_handler (handlers, CONDITION_CASE); | ||
| 1461 | if (sys_setjmp (c->jmp)) | ||
| 1462 | { | ||
| 1463 | Lisp_Object val = handlerlist->val; | ||
| 1464 | clobbered_eassert (handlerlist == c); | ||
| 1465 | handlerlist = handlerlist->next; | ||
| 1466 | return hfun (val); | ||
| 1467 | } | ||
| 1468 | else | ||
| 1469 | { | ||
| 1470 | Lisp_Object val = bfun (arg1, arg2, arg3, arg4); | ||
| 1471 | eassert (handlerlist == c); | ||
| 1472 | handlerlist = c->next; | ||
| 1473 | return val; | ||
| 1474 | } | ||
| 1475 | } | ||
| 1476 | |||
| 1422 | /* Like internal_condition_case but call BFUN with NARGS as first, | 1477 | /* Like internal_condition_case but call BFUN with NARGS as first, |
| 1423 | and ARGS as second argument. */ | 1478 | and ARGS as second argument. */ |
| 1424 | 1479 | ||
diff --git a/src/lisp.h b/src/lisp.h index 4c0057b2552..52242791aa5 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -4165,6 +4165,8 @@ extern Lisp_Object internal_lisp_condition_case (Lisp_Object, Lisp_Object, Lisp_ | |||
| 4165 | extern Lisp_Object internal_condition_case (Lisp_Object (*) (void), Lisp_Object, Lisp_Object (*) (Lisp_Object)); | 4165 | extern Lisp_Object internal_condition_case (Lisp_Object (*) (void), Lisp_Object, Lisp_Object (*) (Lisp_Object)); |
| 4166 | extern Lisp_Object internal_condition_case_1 (Lisp_Object (*) (Lisp_Object), Lisp_Object, Lisp_Object, Lisp_Object (*) (Lisp_Object)); | 4166 | extern Lisp_Object internal_condition_case_1 (Lisp_Object (*) (Lisp_Object), Lisp_Object, Lisp_Object, Lisp_Object (*) (Lisp_Object)); |
| 4167 | extern Lisp_Object internal_condition_case_2 (Lisp_Object (*) (Lisp_Object, Lisp_Object), Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object (*) (Lisp_Object)); | 4167 | extern Lisp_Object internal_condition_case_2 (Lisp_Object (*) (Lisp_Object, Lisp_Object), Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object (*) (Lisp_Object)); |
| 4168 | extern Lisp_Object internal_condition_case_3 (Lisp_Object (*) (Lisp_Object, Lisp_Object, Lisp_Object), Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object (*) (Lisp_Object)); | ||
| 4169 | extern Lisp_Object internal_condition_case_4 (Lisp_Object (*) (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object), Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object (*) (Lisp_Object)); | ||
| 4168 | extern Lisp_Object internal_condition_case_n | 4170 | extern Lisp_Object internal_condition_case_n |
| 4169 | (Lisp_Object (*) (ptrdiff_t, Lisp_Object *), ptrdiff_t, Lisp_Object *, | 4171 | (Lisp_Object (*) (ptrdiff_t, Lisp_Object *), ptrdiff_t, Lisp_Object *, |
| 4170 | Lisp_Object, Lisp_Object (*) (Lisp_Object, ptrdiff_t, Lisp_Object *)); | 4172 | Lisp_Object, Lisp_Object (*) (Lisp_Object, ptrdiff_t, Lisp_Object *)); |
diff --git a/src/pdumper.c b/src/pdumper.c index a6d12b6ea0c..26480388d59 100644 --- a/src/pdumper.c +++ b/src/pdumper.c | |||
| @@ -5312,6 +5312,9 @@ dump_do_dump_relocation (const uintptr_t dump_base, | |||
| 5312 | concat2 (Vinvocation_directory, | 5312 | concat2 (Vinvocation_directory, |
| 5313 | installation_state == LOCAL_BUILD | 5313 | installation_state == LOCAL_BUILD |
| 5314 | ? XCDR (comp_u->file) : XCAR (comp_u->file)); | 5314 | ? XCDR (comp_u->file) : XCAR (comp_u->file)); |
| 5315 | #ifdef WINDOWSNT | ||
| 5316 | comp_u->cfile = xlispstrdup(comp_u->file); | ||
| 5317 | #endif | ||
| 5315 | comp_u->handle = dynlib_open (SSDATA (comp_u->file)); | 5318 | comp_u->handle = dynlib_open (SSDATA (comp_u->file)); |
| 5316 | if (!comp_u->handle) | 5319 | if (!comp_u->handle) |
| 5317 | error ("%s", dynlib_error ()); | 5320 | error ("%s", dynlib_error ()); |