diff options
| author | Andrea Corallo | 2020-05-02 17:29:11 +0100 |
|---|---|---|
| committer | Andrea Corallo | 2020-05-15 20:06:49 +0100 |
| commit | 44b0ce6e38f06df10b60ffdd9d9ade4b7e229088 (patch) | |
| tree | 6747059990968a57a6c7c75b7da1e1cd5f9ae287 /src | |
| parent | 49f0331f53fb9eaa2039538a983eb7b6dbcd206f (diff) | |
| download | emacs-44b0ce6e38f06df10b60ffdd9d9ade4b7e229088.tar.gz emacs-44b0ce6e38f06df10b60ffdd9d9ade4b7e229088.zip | |
Add anonymous lambdas reload mechanism
* src/pdumper.c (dump_do_dump_relocation): Initialize
'lambda_gc_guard' while resurrecting.
(dump_do_dump_relocation): Revive lambdas and fixup them.
* src/comp.h (struct Lisp_Native_Comp_Unit): Define new
'lambda_gc_guard' 'lambda_c_name_idx_h' 'data_imp_relocs'
'loaded_once' fields.
* src/comp.c (load_comp_unit): Use compilaiton unit 'loaded_once'
field.
(make_subr, Fcomp__register_lambda): New functions.
(Fcomp__register_subr): Make use of 'make_subr'.
(Fnative_elisp_load): Indent.
(Fnative_elisp_load): Initialize 'lambda_gc_guard'
'lambda_c_name_idx_h' fields.
(syms_of_comp): Add Scomp__register_lambda.
* lisp/emacs-lisp/comp.el (comp-ctxt): Change
'byte-func-to-func-h' hash key test.
(comp-ctxt): Add 'lambda-fixups-h' slot.
(comp-emit-lambda-for-top-level): New function.
(comp-finalize-relocs): Never emit lambdas in pure space.
(comp-finalize-relocs): Fixup relocation indexes.
Diffstat (limited to 'src')
| -rw-r--r-- | src/comp.c | 88 | ||||
| -rw-r--r-- | src/comp.h | 14 | ||||
| -rw-r--r-- | src/pdumper.c | 18 |
3 files changed, 97 insertions, 23 deletions
diff --git a/src/comp.c b/src/comp.c index 947da9a8e27..5ace2d28052 100644 --- a/src/comp.c +++ b/src/comp.c | |||
| @@ -3583,15 +3583,15 @@ load_comp_unit (struct Lisp_Native_Comp_Unit *comp_u, bool loading_dump, | |||
| 3583 | Lisp_Object *saved_cu = dynlib_sym (handle, COMP_UNIT_SYM); | 3583 | Lisp_Object *saved_cu = dynlib_sym (handle, COMP_UNIT_SYM); |
| 3584 | if (!saved_cu) | 3584 | if (!saved_cu) |
| 3585 | xsignal1 (Qnative_lisp_file_inconsistent, comp_u->file); | 3585 | xsignal1 (Qnative_lisp_file_inconsistent, comp_u->file); |
| 3586 | bool reloading_cu = !NILP (*saved_cu); | 3586 | comp_u->loaded_once = !NILP (*saved_cu); |
| 3587 | Lisp_Object *data_eph_relocs = | 3587 | Lisp_Object *data_eph_relocs = |
| 3588 | dynlib_sym (handle, DATA_RELOC_EPHEMERAL_SYM); | 3588 | dynlib_sym (handle, DATA_RELOC_EPHEMERAL_SYM); |
| 3589 | 3589 | ||
| 3590 | /* While resurrecting from an image dump loading more than once the | 3590 | /* While resurrecting from an image dump loading more than once the |
| 3591 | same compilation unit does not make any sense. */ | 3591 | same compilation unit does not make any sense. */ |
| 3592 | eassert (!(loading_dump && reloading_cu)); | 3592 | eassert (!(loading_dump && comp_u->loaded_once)); |
| 3593 | 3593 | ||
| 3594 | if (reloading_cu) | 3594 | if (comp_u->loaded_once) |
| 3595 | /* 'dlopen' returns the same handle when trying to load two times | 3595 | /* 'dlopen' returns the same handle when trying to load two times |
| 3596 | the same shared. In this case touching 'd_reloc' etc leads to | 3596 | the same shared. In this case touching 'd_reloc' etc leads to |
| 3597 | fails in case a frame with a reference to it in a live reg is | 3597 | fails in case a frame with a reference to it in a live reg is |
| @@ -3612,13 +3612,17 @@ load_comp_unit (struct Lisp_Native_Comp_Unit *comp_u, bool loading_dump, | |||
| 3612 | = dynlib_sym (handle, | 3612 | = dynlib_sym (handle, |
| 3613 | late_load ? "late_top_level_run" : "top_level_run"); | 3613 | late_load ? "late_top_level_run" : "top_level_run"); |
| 3614 | 3614 | ||
| 3615 | if (!reloading_cu) | 3615 | /* Always set data_imp_relocs pointer in the compilation unit (in can be |
| 3616 | used in 'dump_do_dump_relocation'). */ | ||
| 3617 | comp_u->data_imp_relocs = dynlib_sym (handle, DATA_RELOC_IMPURE_SYM); | ||
| 3618 | |||
| 3619 | if (!comp_u->loaded_once) | ||
| 3616 | { | 3620 | { |
| 3617 | struct thread_state ***current_thread_reloc = | 3621 | struct thread_state ***current_thread_reloc = |
| 3618 | dynlib_sym (handle, CURRENT_THREAD_RELOC_SYM); | 3622 | dynlib_sym (handle, CURRENT_THREAD_RELOC_SYM); |
| 3619 | EMACS_INT ***pure_reloc = dynlib_sym (handle, PURE_RELOC_SYM); | 3623 | EMACS_INT ***pure_reloc = dynlib_sym (handle, PURE_RELOC_SYM); |
| 3620 | Lisp_Object *data_relocs = dynlib_sym (handle, DATA_RELOC_SYM); | 3624 | Lisp_Object *data_relocs = dynlib_sym (handle, DATA_RELOC_SYM); |
| 3621 | Lisp_Object *data_imp_relocs = dynlib_sym (handle, DATA_RELOC_IMPURE_SYM); | 3625 | Lisp_Object *data_imp_relocs = comp_u->data_imp_relocs; |
| 3622 | void **freloc_link_table = dynlib_sym (handle, FUNC_LINK_TABLE_SYM); | 3626 | void **freloc_link_table = dynlib_sym (handle, FUNC_LINK_TABLE_SYM); |
| 3623 | 3627 | ||
| 3624 | if (!(current_thread_reloc | 3628 | if (!(current_thread_reloc |
| @@ -3704,15 +3708,13 @@ native_function_doc (Lisp_Object function) | |||
| 3704 | return AREF (cu->data_fdoc_v, XSUBR (function)->doc); | 3708 | return AREF (cu->data_fdoc_v, XSUBR (function)->doc); |
| 3705 | } | 3709 | } |
| 3706 | 3710 | ||
| 3707 | DEFUN ("comp--register-subr", Fcomp__register_subr, Scomp__register_subr, | 3711 | static Lisp_Object |
| 3708 | 7, 7, 0, | 3712 | make_subr (Lisp_Object symbol_name, Lisp_Object minarg, Lisp_Object maxarg, |
| 3709 | doc: /* This gets called by top_level_run during load phase to register | 3713 | Lisp_Object c_name, Lisp_Object doc_idx, Lisp_Object intspec, |
| 3710 | each exported subr. */) | 3714 | Lisp_Object comp_u) |
| 3711 | (Lisp_Object name, Lisp_Object minarg, Lisp_Object maxarg, | ||
| 3712 | Lisp_Object c_name, Lisp_Object doc_idx, Lisp_Object intspec, | ||
| 3713 | Lisp_Object comp_u) | ||
| 3714 | { | 3715 | { |
| 3715 | dynlib_handle_ptr handle = XNATIVE_COMP_UNIT (comp_u)->handle; | 3716 | struct Lisp_Native_Comp_Unit *cu = XNATIVE_COMP_UNIT (comp_u); |
| 3717 | dynlib_handle_ptr handle = cu->handle; | ||
| 3716 | if (!handle) | 3718 | if (!handle) |
| 3717 | xsignal0 (Qwrong_register_subr_call); | 3719 | xsignal0 (Qwrong_register_subr_call); |
| 3718 | 3720 | ||
| @@ -3727,18 +3729,63 @@ DEFUN ("comp--register-subr", Fcomp__register_subr, Scomp__register_subr, | |||
| 3727 | x->s.function.a0 = func; | 3729 | x->s.function.a0 = func; |
| 3728 | x->s.min_args = XFIXNUM (minarg); | 3730 | x->s.min_args = XFIXNUM (minarg); |
| 3729 | x->s.max_args = FIXNUMP (maxarg) ? XFIXNUM (maxarg) : MANY; | 3731 | x->s.max_args = FIXNUMP (maxarg) ? XFIXNUM (maxarg) : MANY; |
| 3730 | x->s.symbol_name = xstrdup (SSDATA (Fsymbol_name (name))); | 3732 | x->s.symbol_name = xstrdup (SSDATA (symbol_name)); |
| 3731 | x->s.native_intspec = intspec; | 3733 | x->s.native_intspec = intspec; |
| 3732 | x->s.doc = XFIXNUM (doc_idx); | 3734 | x->s.doc = XFIXNUM (doc_idx); |
| 3733 | x->s.native_comp_u[0] = comp_u; | 3735 | x->s.native_comp_u[0] = comp_u; |
| 3734 | Lisp_Object tem; | 3736 | Lisp_Object tem; |
| 3735 | XSETSUBR (tem, &x->s); | 3737 | XSETSUBR (tem, &x->s); |
| 3736 | set_symbol_function (name, tem); | ||
| 3737 | 3738 | ||
| 3738 | Fputhash (name, c_name, Vcomp_sym_subr_c_name_h); | 3739 | return tem; |
| 3740 | } | ||
| 3741 | |||
| 3742 | DEFUN ("comp--register-lambda", Fcomp__register_lambda, Scomp__register_lambda, | ||
| 3743 | 7, 7, 0, | ||
| 3744 | doc: /* This gets called by top_level_run during load phase to register | ||
| 3745 | anonymous lambdas. */) | ||
| 3746 | (Lisp_Object reloc_idx, Lisp_Object minarg, Lisp_Object maxarg, | ||
| 3747 | Lisp_Object c_name, Lisp_Object doc_idx, Lisp_Object intspec, | ||
| 3748 | Lisp_Object comp_u) | ||
| 3749 | { | ||
| 3750 | struct Lisp_Native_Comp_Unit *cu = XNATIVE_COMP_UNIT (comp_u); | ||
| 3751 | if (cu->loaded_once) | ||
| 3752 | return Qnil; | ||
| 3753 | |||
| 3754 | Lisp_Object tem = | ||
| 3755 | make_subr (c_name, minarg, maxarg, c_name, doc_idx, intspec, comp_u); | ||
| 3756 | |||
| 3757 | /* We must protect it against GC because the function is not | ||
| 3758 | reachable through symbols. */ | ||
| 3759 | Fputhash (tem, Qt, cu->lambda_gc_guard); | ||
| 3760 | /* This is for fixing up the value in d_reloc while resurrecting | ||
| 3761 | from dump. See 'dump_do_dump_relocation'. */ | ||
| 3762 | Fputhash (c_name, reloc_idx, cu->lambda_c_name_idx_h); | ||
| 3763 | /* The key is not really important as long is the same as | ||
| 3764 | symbol_name so use c_name. */ | ||
| 3765 | Fputhash (Fintern (c_name, Qnil), c_name, Vcomp_sym_subr_c_name_h); | ||
| 3766 | /* Do the real relocation fixup. */ | ||
| 3767 | cu->data_imp_relocs[XFIXNUM (reloc_idx)] = tem; | ||
| 3768 | |||
| 3769 | return tem; | ||
| 3770 | } | ||
| 3771 | |||
| 3772 | DEFUN ("comp--register-subr", Fcomp__register_subr, Scomp__register_subr, | ||
| 3773 | 7, 7, 0, | ||
| 3774 | doc: /* This gets called by top_level_run during load phase to register | ||
| 3775 | each exported subr. */) | ||
| 3776 | (Lisp_Object name, Lisp_Object minarg, Lisp_Object maxarg, | ||
| 3777 | Lisp_Object c_name, Lisp_Object doc_idx, Lisp_Object intspec, | ||
| 3778 | Lisp_Object comp_u) | ||
| 3779 | { | ||
| 3780 | Lisp_Object tem = | ||
| 3781 | make_subr (SYMBOL_NAME (name), minarg, maxarg, c_name, doc_idx, intspec, | ||
| 3782 | comp_u); | ||
| 3783 | |||
| 3784 | set_symbol_function (name, tem); | ||
| 3739 | LOADHIST_ATTACH (Fcons (Qdefun, name)); | 3785 | LOADHIST_ATTACH (Fcons (Qdefun, name)); |
| 3786 | Fputhash (name, c_name, Vcomp_sym_subr_c_name_h); | ||
| 3740 | 3787 | ||
| 3741 | return Qnil; | 3788 | return tem; |
| 3742 | } | 3789 | } |
| 3743 | 3790 | ||
| 3744 | DEFUN ("comp--late-register-subr", Fcomp__late_register_subr, | 3791 | DEFUN ("comp--late-register-subr", Fcomp__late_register_subr, |
| @@ -3759,8 +3806,8 @@ DEFUN ("comp--late-register-subr", Fcomp__late_register_subr, | |||
| 3759 | /* Load related routines. */ | 3806 | /* Load related routines. */ |
| 3760 | DEFUN ("native-elisp-load", Fnative_elisp_load, Snative_elisp_load, 1, 2, 0, | 3807 | DEFUN ("native-elisp-load", Fnative_elisp_load, Snative_elisp_load, 1, 2, 0, |
| 3761 | doc: /* Load native elisp code FILE. | 3808 | doc: /* Load native elisp code FILE. |
| 3762 | LATE_LOAD has to be non nil when loading for deferred | 3809 | LATE_LOAD has to be non nil when loading for deferred |
| 3763 | compilation. */) | 3810 | compilation. */) |
| 3764 | (Lisp_Object file, Lisp_Object late_load) | 3811 | (Lisp_Object file, Lisp_Object late_load) |
| 3765 | { | 3812 | { |
| 3766 | CHECK_STRING (file); | 3813 | CHECK_STRING (file); |
| @@ -3773,6 +3820,8 @@ DEFUN ("native-elisp-load", Fnative_elisp_load, Snative_elisp_load, 1, 2, 0, | |||
| 3773 | xsignal2 (Qnative_lisp_load_failed, file, build_string (dynlib_error ())); | 3820 | xsignal2 (Qnative_lisp_load_failed, file, build_string (dynlib_error ())); |
| 3774 | comp_u->file = file; | 3821 | comp_u->file = file; |
| 3775 | comp_u->data_vec = Qnil; | 3822 | comp_u->data_vec = Qnil; |
| 3823 | comp_u->lambda_gc_guard = CALLN (Fmake_hash_table, QCtest, Qeq); | ||
| 3824 | comp_u->lambda_c_name_idx_h = CALLN (Fmake_hash_table, QCtest, Qequal); | ||
| 3776 | load_comp_unit (comp_u, false, !NILP (late_load)); | 3825 | load_comp_unit (comp_u, false, !NILP (late_load)); |
| 3777 | 3826 | ||
| 3778 | return Qt; | 3827 | return Qt; |
| @@ -3886,6 +3935,7 @@ syms_of_comp (void) | |||
| 3886 | defsubr (&Scomp__init_ctxt); | 3935 | defsubr (&Scomp__init_ctxt); |
| 3887 | defsubr (&Scomp__release_ctxt); | 3936 | defsubr (&Scomp__release_ctxt); |
| 3888 | defsubr (&Scomp__compile_ctxt_to_file); | 3937 | defsubr (&Scomp__compile_ctxt_to_file); |
| 3938 | defsubr (&Scomp__register_lambda); | ||
| 3889 | defsubr (&Scomp__register_subr); | 3939 | defsubr (&Scomp__register_subr); |
| 3890 | defsubr (&Scomp__late_register_subr); | 3940 | defsubr (&Scomp__late_register_subr); |
| 3891 | defsubr (&Snative_elisp_load); | 3941 | defsubr (&Snative_elisp_load); |
diff --git a/src/comp.h b/src/comp.h index cbdcaccd5fe..b03a8055142 100644 --- a/src/comp.h +++ b/src/comp.h | |||
| @@ -37,13 +37,21 @@ struct Lisp_Native_Comp_Unit | |||
| 37 | /* Original eln file loaded. */ | 37 | /* Original eln file loaded. */ |
| 38 | Lisp_Object file; | 38 | Lisp_Object file; |
| 39 | Lisp_Object optimize_qualities; | 39 | Lisp_Object optimize_qualities; |
| 40 | /* Hash doc-idx -> function documentaiton. */ | 40 | /* Guard anonymous lambdas against Garbage Collection and make them |
| 41 | dumpable. */ | ||
| 42 | Lisp_Object lambda_gc_guard; | ||
| 43 | /* Hash c_name -> d_reloc_imp index. */ | ||
| 44 | Lisp_Object lambda_c_name_idx_h; | ||
| 45 | /* Hash doc-idx -> function documentaiton. */ | ||
| 41 | Lisp_Object data_fdoc_v; | 46 | Lisp_Object data_fdoc_v; |
| 42 | /* Analogous to the constant vector but per compilation unit. */ | 47 | /* Analogous to the constant vector but per compilation unit. */ |
| 43 | Lisp_Object data_vec; | 48 | Lisp_Object data_vec; |
| 44 | /* Same but for data that cannot be moved to pure space. | 49 | /* 'data_impure_vec' must be last (see allocate_native_comp_unit). |
| 45 | Must be the last lisp object here. */ | 50 | Same as data_vec but for data that cannot be moved to pure space. */ |
| 46 | Lisp_Object data_impure_vec; | 51 | Lisp_Object data_impure_vec; |
| 52 | /* STUFFS WE DO NOT DUMP!! */ | ||
| 53 | Lisp_Object *data_imp_relocs; | ||
| 54 | bool loaded_once; | ||
| 47 | dynlib_handle_ptr handle; | 55 | dynlib_handle_ptr handle; |
| 48 | }; | 56 | }; |
| 49 | 57 | ||
diff --git a/src/pdumper.c b/src/pdumper.c index f837dfc38d2..a1b71e87ac6 100644 --- a/src/pdumper.c +++ b/src/pdumper.c | |||
| @@ -5297,7 +5297,7 @@ dump_do_dump_relocation (const uintptr_t dump_base, | |||
| 5297 | static enum { UNKNOWN, LOCAL_BUILD, INSTALLED } installation_state; | 5297 | static enum { UNKNOWN, LOCAL_BUILD, INSTALLED } installation_state; |
| 5298 | struct Lisp_Native_Comp_Unit *comp_u = | 5298 | struct Lisp_Native_Comp_Unit *comp_u = |
| 5299 | dump_ptr (dump_base, reloc_offset); | 5299 | dump_ptr (dump_base, reloc_offset); |
| 5300 | 5300 | comp_u->lambda_gc_guard = CALLN (Fmake_hash_table, QCtest, Qeq); | |
| 5301 | if (!CONSP (comp_u->file)) | 5301 | if (!CONSP (comp_u->file)) |
| 5302 | error ("Trying to load incoherent dumped .eln"); | 5302 | error ("Trying to load incoherent dumped .eln"); |
| 5303 | 5303 | ||
| @@ -5320,6 +5320,10 @@ dump_do_dump_relocation (const uintptr_t dump_base, | |||
| 5320 | } | 5320 | } |
| 5321 | case RELOC_NATIVE_SUBR: | 5321 | case RELOC_NATIVE_SUBR: |
| 5322 | { | 5322 | { |
| 5323 | /* When resurrecting from a dump given non all the original | ||
| 5324 | native compiled subrs may be still around we can't rely on | ||
| 5325 | a 'top_level_run' mechanism, we revive them one-by-one | ||
| 5326 | here. */ | ||
| 5323 | struct Lisp_Subr *subr = dump_ptr (dump_base, reloc_offset); | 5327 | struct Lisp_Subr *subr = dump_ptr (dump_base, reloc_offset); |
| 5324 | Lisp_Object name = intern (subr->symbol_name); | 5328 | Lisp_Object name = intern (subr->symbol_name); |
| 5325 | struct Lisp_Native_Comp_Unit *comp_u = | 5329 | struct Lisp_Native_Comp_Unit *comp_u = |
| @@ -5333,6 +5337,18 @@ dump_do_dump_relocation (const uintptr_t dump_base, | |||
| 5333 | if (!func) | 5337 | if (!func) |
| 5334 | error ("can't find function in compilation unit"); | 5338 | error ("can't find function in compilation unit"); |
| 5335 | subr->function.a0 = func; | 5339 | subr->function.a0 = func; |
| 5340 | Lisp_Object lambda_data_idx = | ||
| 5341 | Fgethash (c_name, comp_u->lambda_c_name_idx_h, Qnil); | ||
| 5342 | if (!NILP (lambda_data_idx)) | ||
| 5343 | { | ||
| 5344 | /* This is an anonymous lambda. | ||
| 5345 | We must fixup data_vec so the lambda can be referenced | ||
| 5346 | by code. */ | ||
| 5347 | Lisp_Object tem; | ||
| 5348 | XSETSUBR (tem, subr); | ||
| 5349 | comp_u->data_imp_relocs[XFIXNUM (lambda_data_idx)] = tem; | ||
| 5350 | Fputhash (tem, Qnil, comp_u->lambda_gc_guard); | ||
| 5351 | } | ||
| 5336 | break; | 5352 | break; |
| 5337 | } | 5353 | } |
| 5338 | #endif | 5354 | #endif |