aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndrea Corallo2020-05-02 17:29:11 +0100
committerAndrea Corallo2020-05-15 20:06:49 +0100
commit44b0ce6e38f06df10b60ffdd9d9ade4b7e229088 (patch)
tree6747059990968a57a6c7c75b7da1e1cd5f9ae287 /src
parent49f0331f53fb9eaa2039538a983eb7b6dbcd206f (diff)
downloademacs-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.c88
-rw-r--r--src/comp.h14
-rw-r--r--src/pdumper.c18
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
3707DEFUN ("comp--register-subr", Fcomp__register_subr, Scomp__register_subr, 3711static Lisp_Object
3708 7, 7, 0, 3712make_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
3742DEFUN ("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
3772DEFUN ("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
3744DEFUN ("comp--late-register-subr", Fcomp__late_register_subr, 3791DEFUN ("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. */
3760DEFUN ("native-elisp-load", Fnative_elisp_load, Snative_elisp_load, 1, 2, 0, 3807DEFUN ("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