To: vim_dev@googlegroups.com Subject: Patch 9.0.0398 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.0398 Problem: Members of funccall_T are inconsistently named. Solution: Use the "fc_" prefix for all members. Files: src/structs.h, src/profiler.c, src/userfunc.c, src/vim9execute.c, src/evalvars.c *** ../vim-9.0.0397/src/structs.h 2022-09-06 18:31:09.074310277 +0100 --- src/structs.h 2022-09-06 18:53:35.296180233 +0100 *************** *** 1735,1774 **** */ struct funccall_S { ! ufunc_T *func; // function being called ! int linenr; // next line to be executed ! int returned; // ":return" used struct // fixed variables for arguments { dictitem_T var; // variable (without room for name) char_u room[VAR_SHORT_LEN]; // room for the name ! } fixvar[FIXVAR_CNT]; ! dict_T l_vars; // l: local function variables ! dictitem_T l_vars_var; // variable for l: scope ! dict_T l_avars; // a: argument variables ! dictitem_T l_avars_var; // variable for a: scope ! list_T l_varlist; // list for a:000 ! listitem_T l_listitems[MAX_FUNC_ARGS]; // listitems for a:000 ! typval_T *rettv; // return value ! linenr_T breakpoint; // next line with breakpoint or zero ! int dbg_tick; // debug_tick when breakpoint was set ! int level; // top nesting level of executed function garray_T fc_defer; // functions to be called on return ectx_T *fc_ectx; // execution context for :def function, NULL // otherwise #ifdef FEAT_PROFILE ! proftime_T prof_child; // time spent in a child #endif ! funccall_T *caller; // calling function or NULL; or next funccal in // list pointed to by previous_funccal. // for closure int fc_refcount; // number of user functions that reference this // funccal int fc_copyID; // for garbage collection ! garray_T fc_funcs; // list of ufunc_T* which keep a reference to // "func" }; --- 1735,1774 ---- */ struct funccall_S { ! ufunc_T *fc_func; // function being called ! int fc_linenr; // next line to be executed ! int fc_returned; // ":return" used struct // fixed variables for arguments { dictitem_T var; // variable (without room for name) char_u room[VAR_SHORT_LEN]; // room for the name ! } fc_fixvar[FIXVAR_CNT]; ! dict_T fc_l_vars; // l: local function variables ! dictitem_T fc_l_vars_var; // variable for l: scope ! dict_T fc_l_avars; // a: argument variables ! dictitem_T fc_l_avars_var; // variable for a: scope ! list_T fc_l_varlist; // list for a:000 ! listitem_T fc_l_listitems[MAX_FUNC_ARGS]; // listitems for a:000 ! typval_T *fc_rettv; // return value ! linenr_T fc_breakpoint; // next line with breakpoint or zero ! int fc_dbg_tick; // debug_tick when breakpoint was set ! int fc_level; // top nesting level of executed function garray_T fc_defer; // functions to be called on return ectx_T *fc_ectx; // execution context for :def function, NULL // otherwise #ifdef FEAT_PROFILE ! proftime_T fc_prof_child; // time spent in a child #endif ! funccall_T *fc_caller; // calling function or NULL; or next funccal in // list pointed to by previous_funccal. // for closure int fc_refcount; // number of user functions that reference this // funccal int fc_copyID; // for garbage collection ! garray_T fc_ufuncs; // list of ufunc_T* which keep a reference to // "func" }; *** ../vim-9.0.0397/src/profiler.c 2022-05-28 13:38:55.000000000 +0100 --- src/profiler.c 2022-09-06 18:46:14.653046563 +0100 *************** *** 718,725 **** { funccall_T *fc = get_current_funccal(); ! if (fc != NULL && fc->func->uf_profiling) ! profile_start(&fc->prof_child); script_prof_save(tm); } --- 718,725 ---- { funccall_T *fc = get_current_funccal(); ! if (fc != NULL && fc->fc_func->uf_profiling) ! profile_start(&fc->fc_prof_child); script_prof_save(tm); } *************** *** 733,744 **** { funccall_T *fc = get_current_funccal(); ! if (fc != NULL && fc->func->uf_profiling) { ! profile_end(&fc->prof_child); ! profile_sub_wait(tm, &fc->prof_child); // don't count waiting time ! profile_add(&fc->func->uf_tm_children, &fc->prof_child); ! profile_add(&fc->func->uf_tml_children, &fc->prof_child); } script_prof_restore(tm); } --- 733,744 ---- { funccall_T *fc = get_current_funccal(); ! if (fc != NULL && fc->fc_func->uf_profiling) { ! profile_end(&fc->fc_prof_child); ! profile_sub_wait(tm, &fc->fc_prof_child); // don't count waiting time ! profile_add(&fc->fc_func->uf_tm_children, &fc->fc_prof_child); ! profile_add(&fc->fc_func->uf_tml_children, &fc->fc_prof_child); } script_prof_restore(tm); } *************** *** 753,759 **** func_line_start(void *cookie, long lnum) { funccall_T *fcp = (funccall_T *)cookie; ! ufunc_T *fp = fcp->func; if (fp->uf_profiling && lnum >= 1 && lnum <= fp->uf_lines.ga_len) { --- 753,759 ---- func_line_start(void *cookie, long lnum) { funccall_T *fcp = (funccall_T *)cookie; ! ufunc_T *fp = fcp->fc_func; if (fp->uf_profiling && lnum >= 1 && lnum <= fp->uf_lines.ga_len) { *************** *** 775,781 **** func_line_exec(void *cookie) { funccall_T *fcp = (funccall_T *)cookie; ! ufunc_T *fp = fcp->func; if (fp->uf_profiling && fp->uf_tml_idx >= 0) fp->uf_tml_execed = TRUE; --- 775,781 ---- func_line_exec(void *cookie) { funccall_T *fcp = (funccall_T *)cookie; ! ufunc_T *fp = fcp->fc_func; if (fp->uf_profiling && fp->uf_tml_idx >= 0) fp->uf_tml_execed = TRUE; *************** *** 788,794 **** func_line_end(void *cookie) { funccall_T *fcp = (funccall_T *)cookie; ! ufunc_T *fp = fcp->func; if (fp->uf_profiling && fp->uf_tml_idx >= 0) { --- 788,794 ---- func_line_end(void *cookie) { funccall_T *fcp = (funccall_T *)cookie; ! ufunc_T *fp = fcp->fc_func; if (fp->uf_profiling && fp->uf_tml_idx >= 0) { *** ../vim-9.0.0397/src/userfunc.c 2022-09-06 18:31:09.070310282 +0100 --- src/userfunc.c 2022-09-06 18:54:28.732071228 +0100 *************** *** 499,508 **** fp->uf_scoped = current_funccal; current_funccal->fc_refcount++; ! if (ga_grow(¤t_funccal->fc_funcs, 1) == FAIL) return FAIL; ! ((ufunc_T **)current_funccal->fc_funcs.ga_data) ! [current_funccal->fc_funcs.ga_len++] = fp; return OK; } --- 499,508 ---- fp->uf_scoped = current_funccal; current_funccal->fc_refcount++; ! if (ga_grow(¤t_funccal->fc_ufuncs, 1) == FAIL) return FAIL; ! ((ufunc_T **)current_funccal->fc_ufuncs.ga_data) ! [current_funccal->fc_ufuncs.ga_len++] = fp; return OK; } *************** *** 2141,2149 **** { int i; ! for (i = 0; i < fc->fc_funcs.ga_len; ++i) { ! ufunc_T *fp = ((ufunc_T **)(fc->fc_funcs.ga_data))[i]; // When garbage collecting a funccall_T may be freed before the // function that references it, clear its uf_scoped field. --- 2141,2149 ---- { int i; ! for (i = 0; i < fc->fc_ufuncs.ga_len; ++i) { ! ufunc_T *fp = ((ufunc_T **)(fc->fc_ufuncs.ga_data))[i]; // When garbage collecting a funccall_T may be freed before the // function that references it, clear its uf_scoped field. *************** *** 2152,2160 **** if (fp != NULL && fp->uf_scoped == fc) fp->uf_scoped = NULL; } ! ga_clear(&fc->fc_funcs); ! func_ptr_unref(fc->func); vim_free(fc); } --- 2152,2160 ---- if (fp != NULL && fp->uf_scoped == fc) fp->uf_scoped = NULL; } ! ga_clear(&fc->fc_ufuncs); ! func_ptr_unref(fc->fc_func); vim_free(fc); } *************** *** 2169,2181 **** listitem_T *li; // Free all l: variables. ! vars_clear(&fc->l_vars.dv_hashtab); // Free all a: variables. ! vars_clear(&fc->l_avars.dv_hashtab); // Free the a:000 variables. ! FOR_ALL_LIST_ITEMS(&fc->l_varlist, li) clear_tv(&li->li_tv); free_funccal(fc); --- 2169,2181 ---- listitem_T *li; // Free all l: variables. ! vars_clear(&fc->fc_l_vars.dv_hashtab); // Free all a: variables. ! vars_clear(&fc->fc_l_avars.dv_hashtab); // Free the a:000 variables. ! FOR_ALL_LIST_ITEMS(&fc->fc_l_varlist, li) clear_tv(&li->li_tv); free_funccal(fc); *************** *** 2191,2209 **** int may_free_fc = fc->fc_refcount <= 0; int free_fc = TRUE; ! current_funccal = fc->caller; // Free all l: variables if not referred. ! if (may_free_fc && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT) ! vars_clear(&fc->l_vars.dv_hashtab); else free_fc = FALSE; // If the a:000 list and the l: and a: dicts are not referenced and // there is no closure using it, we can free the funccall_T and what's // in it. ! if (may_free_fc && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT) ! vars_clear_ext(&fc->l_avars.dv_hashtab, FALSE); else { int todo; --- 2191,2209 ---- int may_free_fc = fc->fc_refcount <= 0; int free_fc = TRUE; ! current_funccal = fc->fc_caller; // Free all l: variables if not referred. ! if (may_free_fc && fc->fc_l_vars.dv_refcount == DO_NOT_FREE_CNT) ! vars_clear(&fc->fc_l_vars.dv_hashtab); else free_fc = FALSE; // If the a:000 list and the l: and a: dicts are not referenced and // there is no closure using it, we can free the funccall_T and what's // in it. ! if (may_free_fc && fc->fc_l_avars.dv_refcount == DO_NOT_FREE_CNT) ! vars_clear_ext(&fc->fc_l_avars.dv_hashtab, FALSE); else { int todo; *************** *** 2213,2220 **** free_fc = FALSE; // Make a copy of the a: variables, since we didn't do that above. ! todo = (int)fc->l_avars.dv_hashtab.ht_used; ! for (hi = fc->l_avars.dv_hashtab.ht_array; todo > 0; ++hi) { if (!HASHITEM_EMPTY(hi)) { --- 2213,2220 ---- free_fc = FALSE; // Make a copy of the a: variables, since we didn't do that above. ! todo = (int)fc->fc_l_avars.dv_hashtab.ht_used; ! for (hi = fc->fc_l_avars.dv_hashtab.ht_array; todo > 0; ++hi) { if (!HASHITEM_EMPTY(hi)) { *************** *** 2225,2232 **** } } ! if (may_free_fc && fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT) ! fc->l_varlist.lv_first = NULL; else { listitem_T *li; --- 2225,2232 ---- } } ! if (may_free_fc && fc->fc_l_varlist.lv_refcount == DO_NOT_FREE_CNT) ! fc->fc_l_varlist.lv_first = NULL; else { listitem_T *li; *************** *** 2234,2240 **** free_fc = FALSE; // Make a copy of the a:000 items, since we didn't do that above. ! FOR_ALL_LIST_ITEMS(&fc->l_varlist, li) copy_tv(&li->li_tv, &li->li_tv); } --- 2234,2240 ---- free_fc = FALSE; // Make a copy of the a:000 items, since we didn't do that above. ! FOR_ALL_LIST_ITEMS(&fc->fc_l_varlist, li) copy_tv(&li->li_tv, &li->li_tv); } *************** *** 2247,2253 **** // "fc" is still in use. This can happen when returning "a:000", // assigning "l:" to a global variable or defining a closure. // Link "fc" in the list for garbage collection later. ! fc->caller = previous_funccal; previous_funccal = fc; if (want_garbage_collect) --- 2247,2253 ---- // "fc" is still in use. This can happen when returning "a:000", // assigning "l:" to a global variable or defining a closure. // Link "fc" in the list for garbage collection later. ! fc->fc_caller = previous_funccal; previous_funccal = fc; if (want_garbage_collect) *************** *** 2305,2325 **** return; if (--fc->fc_refcount <= 0 && (force || ( ! fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT ! && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT ! && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT))) ! for (pfc = &previous_funccal; *pfc != NULL; pfc = &(*pfc)->caller) { if (fc == *pfc) { ! *pfc = fc->caller; free_funccal_contents(fc); return; } } ! for (i = 0; i < fc->fc_funcs.ga_len; ++i) ! if (((ufunc_T **)(fc->fc_funcs.ga_data))[i] == fp) ! ((ufunc_T **)(fc->fc_funcs.ga_data))[i] = NULL; } /* --- 2305,2325 ---- return; if (--fc->fc_refcount <= 0 && (force || ( ! fc->fc_l_varlist.lv_refcount == DO_NOT_FREE_CNT ! && fc->fc_l_vars.dv_refcount == DO_NOT_FREE_CNT ! && fc->fc_l_avars.dv_refcount == DO_NOT_FREE_CNT))) ! for (pfc = &previous_funccal; *pfc != NULL; pfc = &(*pfc)->fc_caller) { if (fc == *pfc) { ! *pfc = fc->fc_caller; free_funccal_contents(fc); return; } } ! for (i = 0; i < fc->fc_ufuncs.ga_len; ++i) ! if (((ufunc_T **)(fc->fc_ufuncs.ga_data))[i] == fp) ! ((ufunc_T **)(fc->fc_ufuncs.ga_data))[i] = NULL; } /* *************** *** 2599,2605 **** int save_did_emsg; int default_arg_err = FALSE; dictitem_T *v; ! int fixvar_idx = 0; // index in fixvar[] int i; int ai; int islambda = FALSE; --- 2599,2605 ---- int save_did_emsg; int default_arg_err = FALSE; dictitem_T *v; ! int fixvar_idx = 0; // index in fc_fixvar[] int i; int ai; int islambda = FALSE; *************** *** 2629,2650 **** fc = ALLOC_CLEAR_ONE(funccall_T); if (fc == NULL) return; ! fc->caller = current_funccal; current_funccal = fc; ! fc->func = fp; ! fc->rettv = rettv; ! fc->level = ex_nesting_level; // Check if this function has a breakpoint. ! fc->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, (linenr_T)0); ! fc->dbg_tick = debug_tick; // Set up fields for closure. ! ga_init2(&fc->fc_funcs, sizeof(ufunc_T *), 1); func_ptr_ref(fp); if (fp->uf_def_status != UF_NOT_COMPILED) { #ifdef FEAT_PROFILE ! ufunc_T *caller = fc->caller == NULL ? NULL : fc->caller->func; #endif // Execute the function, possibly compiling it first. #ifdef FEAT_PROFILE --- 2629,2650 ---- fc = ALLOC_CLEAR_ONE(funccall_T); if (fc == NULL) return; ! fc->fc_caller = current_funccal; current_funccal = fc; ! fc->fc_func = fp; ! fc->fc_rettv = rettv; ! fc->fc_level = ex_nesting_level; // Check if this function has a breakpoint. ! fc->fc_breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, (linenr_T)0); ! fc->fc_dbg_tick = debug_tick; // Set up fields for closure. ! ga_init2(&fc->fc_ufuncs, sizeof(ufunc_T *), 1); func_ptr_ref(fp); if (fp->uf_def_status != UF_NOT_COMPILED) { #ifdef FEAT_PROFILE ! ufunc_T *caller = fc->fc_caller == NULL ? NULL : fc->fc_caller->fc_func; #endif // Execute the function, possibly compiling it first. #ifdef FEAT_PROFILE *************** *** 2660,2666 **** || (caller != NULL && caller->uf_profiling))) profile_may_end_func(&profile_info, fp, caller); #endif ! current_funccal = fc->caller; free_funccal(fc); sticky_cmdmod_flags = save_sticky_cmdmod_flags; return; --- 2660,2666 ---- || (caller != NULL && caller->uf_profiling))) profile_may_end_func(&profile_info, fp, caller); #endif ! current_funccal = fc->fc_caller; free_funccal(fc); sticky_cmdmod_flags = save_sticky_cmdmod_flags; return; *************** *** 2669,2691 **** islambda = fp->uf_flags & FC_LAMBDA; /* ! * Note about using fc->fixvar[]: This is an array of FIXVAR_CNT variables * with names up to VAR_SHORT_LEN long. This avoids having to alloc/free * each argument variable and saves a lot of time. */ /* * Init l: variables. */ ! init_var_dict(&fc->l_vars, &fc->l_vars_var, VAR_DEF_SCOPE); if (selfdict != NULL) { // Set l:self to "selfdict". Use "name" to avoid a warning from // some compiler that checks the destination size. ! v = &fc->fixvar[fixvar_idx++].var; name = v->di_key; STRCPY(name, "self"); v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; ! hash_add(&fc->l_vars.dv_hashtab, DI2HIKEY(v)); v->di_tv.v_type = VAR_DICT; v->di_tv.v_lock = 0; v->di_tv.vval.v_dict = selfdict; --- 2669,2691 ---- islambda = fp->uf_flags & FC_LAMBDA; /* ! * Note about using fc->fc_fixvar[]: This is an array of FIXVAR_CNT variables * with names up to VAR_SHORT_LEN long. This avoids having to alloc/free * each argument variable and saves a lot of time. */ /* * Init l: variables. */ ! init_var_dict(&fc->fc_l_vars, &fc->fc_l_vars_var, VAR_DEF_SCOPE); if (selfdict != NULL) { // Set l:self to "selfdict". Use "name" to avoid a warning from // some compiler that checks the destination size. ! v = &fc->fc_fixvar[fixvar_idx++].var; name = v->di_key; STRCPY(name, "self"); v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; ! hash_add(&fc->fc_l_vars.dv_hashtab, DI2HIKEY(v)); v->di_tv.v_type = VAR_DICT; v->di_tv.v_lock = 0; v->di_tv.vval.v_dict = selfdict; *************** *** 2697,2724 **** * Set a:0 to "argcount" less number of named arguments, if >= 0. * Set a:000 to a list with room for the "..." arguments. */ ! init_var_dict(&fc->l_avars, &fc->l_avars_var, VAR_SCOPE); if ((fp->uf_flags & FC_NOARGS) == 0) ! add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "0", (varnumber_T)(argcount >= fp->uf_args.ga_len ? argcount - fp->uf_args.ga_len : 0)); ! fc->l_avars.dv_lock = VAR_FIXED; if ((fp->uf_flags & FC_NOARGS) == 0) { // Use "name" to avoid a warning from some compiler that checks the // destination size. ! v = &fc->fixvar[fixvar_idx++].var; name = v->di_key; STRCPY(name, "000"); v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; ! hash_add(&fc->l_avars.dv_hashtab, DI2HIKEY(v)); v->di_tv.v_type = VAR_LIST; v->di_tv.v_lock = VAR_FIXED; ! v->di_tv.vval.v_list = &fc->l_varlist; } ! CLEAR_FIELD(fc->l_varlist); ! fc->l_varlist.lv_refcount = DO_NOT_FREE_CNT; ! fc->l_varlist.lv_lock = VAR_FIXED; /* * Set a:firstline to "firstline" and a:lastline to "lastline". --- 2697,2724 ---- * Set a:0 to "argcount" less number of named arguments, if >= 0. * Set a:000 to a list with room for the "..." arguments. */ ! init_var_dict(&fc->fc_l_avars, &fc->fc_l_avars_var, VAR_SCOPE); if ((fp->uf_flags & FC_NOARGS) == 0) ! add_nr_var(&fc->fc_l_avars, &fc->fc_fixvar[fixvar_idx++].var, "0", (varnumber_T)(argcount >= fp->uf_args.ga_len ? argcount - fp->uf_args.ga_len : 0)); ! fc->fc_l_avars.dv_lock = VAR_FIXED; if ((fp->uf_flags & FC_NOARGS) == 0) { // Use "name" to avoid a warning from some compiler that checks the // destination size. ! v = &fc->fc_fixvar[fixvar_idx++].var; name = v->di_key; STRCPY(name, "000"); v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; ! hash_add(&fc->fc_l_avars.dv_hashtab, DI2HIKEY(v)); v->di_tv.v_type = VAR_LIST; v->di_tv.v_lock = VAR_FIXED; ! v->di_tv.vval.v_list = &fc->fc_l_varlist; } ! CLEAR_FIELD(fc->fc_l_varlist); ! fc->fc_l_varlist.lv_refcount = DO_NOT_FREE_CNT; ! fc->fc_l_varlist.lv_lock = VAR_FIXED; /* * Set a:firstline to "firstline" and a:lastline to "lastline". *************** *** 2728,2737 **** */ if ((fp->uf_flags & FC_NOARGS) == 0) { ! add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "firstline", ! (varnumber_T)funcexe->fe_firstline); ! add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "lastline", ! (varnumber_T)funcexe->fe_lastline); } for (i = 0; i < argcount || i < fp->uf_args.ga_len; ++i) { --- 2728,2737 ---- */ if ((fp->uf_flags & FC_NOARGS) == 0) { ! add_nr_var(&fc->fc_l_avars, &fc->fc_fixvar[fixvar_idx++].var, ! "firstline", (varnumber_T)funcexe->fe_firstline); ! add_nr_var(&fc->fc_l_avars, &fc->fc_fixvar[fixvar_idx++].var, ! "lastline", (varnumber_T)funcexe->fe_lastline); } for (i = 0; i < argcount || i < fp->uf_args.ga_len; ++i) { *************** *** 2779,2785 **** } if (fixvar_idx < FIXVAR_CNT && STRLEN(name) <= VAR_SHORT_LEN) { ! v = &fc->fixvar[fixvar_idx++].var; v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; STRCPY(v->di_key, name); } --- 2779,2785 ---- } if (fixvar_idx < FIXVAR_CNT && STRLEN(name) <= VAR_SHORT_LEN) { ! v = &fc->fc_fixvar[fixvar_idx++].var; v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; STRCPY(v->di_key, name); } *************** *** 2805,2822 **** // Named arguments should be accessed without the "a:" prefix in // lambda expressions. Add to the l: dict. copy_tv(&v->di_tv, &v->di_tv); ! hash_add(&fc->l_vars.dv_hashtab, DI2HIKEY(v)); } else ! hash_add(&fc->l_avars.dv_hashtab, DI2HIKEY(v)); if (ai >= 0 && ai < MAX_FUNC_ARGS) { ! listitem_T *li = &fc->l_listitems[ai]; li->li_tv = argvars[i]; li->li_tv.v_lock = VAR_FIXED; ! list_append(&fc->l_varlist, li); } } --- 2805,2822 ---- // Named arguments should be accessed without the "a:" prefix in // lambda expressions. Add to the l: dict. copy_tv(&v->di_tv, &v->di_tv); ! hash_add(&fc->fc_l_vars.dv_hashtab, DI2HIKEY(v)); } else ! hash_add(&fc->fc_l_avars.dv_hashtab, DI2HIKEY(v)); if (ai >= 0 && ai < MAX_FUNC_ARGS) { ! listitem_T *li = &fc->fc_l_listitems[ai]; li->li_tv = argvars[i]; li->li_tv.v_lock = VAR_FIXED; ! list_append(&fc->fc_l_varlist, li); } } *************** *** 2879,2885 **** #ifdef FEAT_PROFILE if (do_profiling == PROF_YES) profile_may_start_func(&profile_info, fp, ! fc->caller == NULL ? NULL : fc->caller->func); #endif // "legacy" does not apply to commands in the function --- 2879,2885 ---- #ifdef FEAT_PROFILE if (do_profiling == PROF_YES) profile_may_start_func(&profile_info, fp, ! fc->fc_caller == NULL ? NULL : fc->fc_caller->fc_func); #endif // "legacy" does not apply to commands in the function *************** *** 2923,2929 **** #ifdef FEAT_PROFILE if (do_profiling == PROF_YES) { ! ufunc_T *caller = fc->caller == NULL ? NULL : fc->caller->func; if (fp->uf_profiling || (caller != NULL && caller->uf_profiling)) profile_may_end_func(&profile_info, fp, caller); --- 2923,2929 ---- #ifdef FEAT_PROFILE if (do_profiling == PROF_YES) { ! ufunc_T *caller = fc->fc_caller == NULL ? NULL : fc->fc_caller->fc_func; if (fp->uf_profiling || (caller != NULL && caller->uf_profiling)) profile_may_end_func(&profile_info, fp, caller); *************** *** 2938,2946 **** if (aborting()) smsg(_("%s aborted"), SOURCING_NAME); ! else if (fc->rettv->v_type == VAR_NUMBER) smsg(_("%s returning #%ld"), SOURCING_NAME, ! (long)fc->rettv->vval.v_number); else { char_u buf[MSG_BUF_LEN]; --- 2938,2946 ---- if (aborting()) smsg(_("%s aborted"), SOURCING_NAME); ! else if (fc->fc_rettv->v_type == VAR_NUMBER) smsg(_("%s returning #%ld"), SOURCING_NAME, ! (long)fc->fc_rettv->vval.v_number); else { char_u buf[MSG_BUF_LEN]; *************** *** 2952,2958 **** // have some idea how it starts and ends. smsg() would always // truncate it at the end. Don't want errors such as E724 here. ++emsg_off; ! s = tv2string(fc->rettv, &tofree, numbuf2, 0); --emsg_off; if (s != NULL) { --- 2952,2958 ---- // have some idea how it starts and ends. smsg() would always // truncate it at the end. Don't want errors such as E724 here. ++emsg_off; ! s = tv2string(fc->fc_rettv, &tofree, numbuf2, 0); --emsg_off; if (s != NULL) { *************** *** 3188,3194 **** // Clean up the current_funccal chain and the funccal stack. while (current_funccal != NULL) { ! clear_tv(current_funccal->rettv); cleanup_function_call(current_funccal); if (current_funccal == NULL && funccal_stack != NULL) restore_funccal(); --- 3188,3194 ---- // Clean up the current_funccal chain and the funccal stack. while (current_funccal != NULL) { ! clear_tv(current_funccal->fc_rettv); cleanup_function_call(current_funccal); if (current_funccal == NULL && funccal_stack != NULL) restore_funccal(); *************** *** 5418,5426 **** static int can_free_funccal(funccall_T *fc, int copyID) { ! return (fc->l_varlist.lv_copyID != copyID ! && fc->l_vars.dv_copyID != copyID ! && fc->l_avars.dv_copyID != copyID && fc->fc_copyID != copyID); } --- 5418,5426 ---- static int can_free_funccal(funccall_T *fc, int copyID) { ! return (fc->fc_l_varlist.lv_copyID != copyID ! && fc->fc_l_vars.dv_copyID != copyID ! && fc->fc_l_avars.dv_copyID != copyID && fc->fc_copyID != copyID); } *************** *** 5696,5702 **** { funccall_T *funccal; ! for (funccal = current_funccal; funccal != NULL; funccal = funccal->caller) if (funccal->fc_ectx != NULL) { // :def function --- 5696,5703 ---- { funccall_T *funccal; ! for (funccal = current_funccal; funccal != NULL; ! funccal = funccal->fc_caller) if (funccal->fc_ectx != NULL) { // :def function *************** *** 5849,5855 **** if (reanimate) // Undo the return. ! current_funccal->returned = FALSE; /* * Cleanup (and inactivate) conditionals, but stop when a try conditional --- 5850,5856 ---- if (reanimate) // Undo the return. ! current_funccal->fc_returned = FALSE; /* * Cleanup (and inactivate) conditionals, but stop when a try conditional *************** *** 5872,5878 **** // When undoing a return in order to make it pending, get the stored // return rettv. if (reanimate) ! rettv = current_funccal->rettv; if (rettv != NULL) { --- 5873,5879 ---- // When undoing a return in order to make it pending, get the stored // return rettv. if (reanimate) ! rettv = current_funccal->fc_rettv; if (rettv != NULL) { *************** *** 5890,5912 **** // The pending return value could be overwritten by a ":return" // without argument in a finally clause; reset the default // return value. ! current_funccal->rettv->v_type = VAR_NUMBER; ! current_funccal->rettv->vval.v_number = 0; } } report_make_pending(CSTP_RETURN, rettv); } else { ! current_funccal->returned = TRUE; // If the return is carried out now, store the return value. For // a return immediately after reanimation, the value is already // there. if (!reanimate && rettv != NULL) { ! clear_tv(current_funccal->rettv); ! *current_funccal->rettv = *(typval_T *)rettv; if (!is_cmd) vim_free(rettv); } --- 5891,5913 ---- // The pending return value could be overwritten by a ":return" // without argument in a finally clause; reset the default // return value. ! current_funccal->fc_rettv->v_type = VAR_NUMBER; ! current_funccal->fc_rettv->vval.v_number = 0; } } report_make_pending(CSTP_RETURN, rettv); } else { ! current_funccal->fc_returned = TRUE; // If the return is carried out now, store the return value. For // a return immediately after reanimation, the value is already // there. if (!reanimate && rettv != NULL) { ! clear_tv(current_funccal->fc_rettv); ! *current_funccal->fc_rettv = *(typval_T *)rettv; if (!is_cmd) vim_free(rettv); } *************** *** 5961,5976 **** getline_opt_T options UNUSED) { funccall_T *fcp = (funccall_T *)cookie; ! ufunc_T *fp = fcp->func; char_u *retval; garray_T *gap; // growarray with function lines // If breakpoints have been added/deleted need to check for it. ! if (fcp->dbg_tick != debug_tick) { ! fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, SOURCING_LNUM); ! fcp->dbg_tick = debug_tick; } #ifdef FEAT_PROFILE if (do_profiling == PROF_YES) --- 5962,5977 ---- getline_opt_T options UNUSED) { funccall_T *fcp = (funccall_T *)cookie; ! ufunc_T *fp = fcp->fc_func; char_u *retval; garray_T *gap; // growarray with function lines // If breakpoints have been added/deleted need to check for it. ! if (fcp->fc_dbg_tick != debug_tick) { ! fcp->fc_breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, SOURCING_LNUM); ! fcp->fc_dbg_tick = debug_tick; } #ifdef FEAT_PROFILE if (do_profiling == PROF_YES) *************** *** 5979,5998 **** gap = &fp->uf_lines; if (((fp->uf_flags & FC_ABORT) && did_emsg && !aborted_in_try()) ! || fcp->returned) retval = NULL; else { // Skip NULL lines (continuation lines). ! while (fcp->linenr < gap->ga_len ! && ((char_u **)(gap->ga_data))[fcp->linenr] == NULL) ! ++fcp->linenr; ! if (fcp->linenr >= gap->ga_len) retval = NULL; else { ! retval = vim_strsave(((char_u **)(gap->ga_data))[fcp->linenr++]); ! SOURCING_LNUM = fcp->linenr; #ifdef FEAT_PROFILE if (do_profiling == PROF_YES) func_line_start(cookie, SOURCING_LNUM); --- 5980,5999 ---- gap = &fp->uf_lines; if (((fp->uf_flags & FC_ABORT) && did_emsg && !aborted_in_try()) ! || fcp->fc_returned) retval = NULL; else { // Skip NULL lines (continuation lines). ! while (fcp->fc_linenr < gap->ga_len ! && ((char_u **)(gap->ga_data))[fcp->fc_linenr] == NULL) ! ++fcp->fc_linenr; ! if (fcp->fc_linenr >= gap->ga_len) retval = NULL; else { ! retval = vim_strsave(((char_u **)(gap->ga_data))[fcp->fc_linenr++]); ! SOURCING_LNUM = fcp->fc_linenr; #ifdef FEAT_PROFILE if (do_profiling == PROF_YES) func_line_start(cookie, SOURCING_LNUM); *************** *** 6001,6013 **** } // Did we encounter a breakpoint? ! if (fcp->breakpoint != 0 && fcp->breakpoint <= SOURCING_LNUM) { dbg_breakpoint(fp->uf_name, SOURCING_LNUM); // Find next breakpoint. ! fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, SOURCING_LNUM); ! fcp->dbg_tick = debug_tick; } return retval; --- 6002,6014 ---- } // Did we encounter a breakpoint? ! if (fcp->fc_breakpoint != 0 && fcp->fc_breakpoint <= SOURCING_LNUM) { dbg_breakpoint(fp->uf_name, SOURCING_LNUM); // Find next breakpoint. ! fcp->fc_breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, SOURCING_LNUM); ! fcp->fc_dbg_tick = debug_tick; } return retval; *************** *** 6024,6031 **** // Ignore the "abort" flag if the abortion behavior has been changed due to // an error inside a try conditional. ! return (((fcp->func->uf_flags & FC_ABORT) && did_emsg && !aborted_in_try()) ! || fcp->returned); } /* --- 6025,6033 ---- // Ignore the "abort" flag if the abortion behavior has been changed due to // an error inside a try conditional. ! return (((fcp->fc_func->uf_flags & FC_ABORT) ! && did_emsg && !aborted_in_try()) ! || fcp->fc_returned); } /* *************** *** 6035,6041 **** func_has_abort( void *cookie) { ! return ((funccall_T *)cookie)->func->uf_flags & FC_ABORT; } --- 6037,6043 ---- func_has_abort( void *cookie) { ! return ((funccall_T *)cookie)->fc_func->uf_flags & FC_ABORT; } *************** *** 6143,6149 **** char_u * func_name(void *cookie) { ! return ((funccall_T *)cookie)->func->uf_name; } /* --- 6145,6151 ---- char_u * func_name(void *cookie) { ! return ((funccall_T *)cookie)->fc_func->uf_name; } /* *************** *** 6152,6158 **** linenr_T * func_breakpoint(void *cookie) { ! return &((funccall_T *)cookie)->breakpoint; } /* --- 6154,6160 ---- linenr_T * func_breakpoint(void *cookie) { ! return &((funccall_T *)cookie)->fc_breakpoint; } /* *************** *** 6161,6167 **** int * func_dbg_tick(void *cookie) { ! return &((funccall_T *)cookie)->dbg_tick; } /* --- 6163,6169 ---- int * func_dbg_tick(void *cookie) { ! return &((funccall_T *)cookie)->fc_dbg_tick; } /* *************** *** 6170,6176 **** int func_level(void *cookie) { ! return ((funccall_T *)cookie)->level; } /* --- 6172,6178 ---- int func_level(void *cookie) { ! return ((funccall_T *)cookie)->fc_level; } /* *************** *** 6179,6185 **** int current_func_returned(void) { ! return current_funccal->returned; } int --- 6181,6187 ---- int current_func_returned(void) { ! return current_funccal->fc_returned; } int *************** *** 6194,6206 **** if (can_free_funccal(*pfc, copyID)) { fc = *pfc; ! *pfc = fc->caller; free_funccal_contents(fc); did_free = TRUE; did_free_funccal = TRUE; } else ! pfc = &(*pfc)->caller; } if (did_free_funccal) // When a funccal was freed some more items might be garbage --- 6196,6208 ---- if (can_free_funccal(*pfc, copyID)) { fc = *pfc; ! *pfc = fc->fc_caller; free_funccal_contents(fc); did_free = TRUE; did_free_funccal = TRUE; } else ! pfc = &(*pfc)->fc_caller; } if (did_free_funccal) // When a funccal was freed some more items might be garbage *************** *** 6225,6231 **** { for (i = 0; i < debug_backtrace_level; i++) { ! temp_funccal = funccal->caller; if (temp_funccal) funccal = temp_funccal; else --- 6227,6233 ---- { for (i = 0; i < debug_backtrace_level; i++) { ! temp_funccal = funccal->fc_caller; if (temp_funccal) funccal = temp_funccal; else *************** *** 6243,6251 **** hashtab_T * get_funccal_local_ht() { ! if (current_funccal == NULL || current_funccal->l_vars.dv_refcount == 0) return NULL; ! return &get_funccal()->l_vars.dv_hashtab; } /* --- 6245,6253 ---- hashtab_T * get_funccal_local_ht() { ! if (current_funccal == NULL || current_funccal->fc_l_vars.dv_refcount == 0) return NULL; ! return &get_funccal()->fc_l_vars.dv_hashtab; } /* *************** *** 6255,6263 **** dictitem_T * get_funccal_local_var() { ! if (current_funccal == NULL || current_funccal->l_vars.dv_refcount == 0) return NULL; ! return &get_funccal()->l_vars_var; } /* --- 6257,6265 ---- dictitem_T * get_funccal_local_var() { ! if (current_funccal == NULL || current_funccal->fc_l_vars.dv_refcount == 0) return NULL; ! return &get_funccal()->fc_l_vars_var; } /* *************** *** 6267,6275 **** hashtab_T * get_funccal_args_ht() { ! if (current_funccal == NULL || current_funccal->l_vars.dv_refcount == 0) return NULL; ! return &get_funccal()->l_avars.dv_hashtab; } /* --- 6269,6277 ---- hashtab_T * get_funccal_args_ht() { ! if (current_funccal == NULL || current_funccal->fc_l_vars.dv_refcount == 0) return NULL; ! return &get_funccal()->fc_l_avars.dv_hashtab; } /* *************** *** 6279,6287 **** dictitem_T * get_funccal_args_var() { ! if (current_funccal == NULL || current_funccal->l_vars.dv_refcount == 0) return NULL; ! return &get_funccal()->l_avars_var; } /* --- 6281,6289 ---- dictitem_T * get_funccal_args_var() { ! if (current_funccal == NULL || current_funccal->fc_l_vars.dv_refcount == 0) return NULL; ! return &get_funccal()->fc_l_avars_var; } /* *************** *** 6290,6297 **** void list_func_vars(int *first) { ! if (current_funccal != NULL && current_funccal->l_vars.dv_refcount > 0) ! list_hashtable_vars(¤t_funccal->l_vars.dv_hashtab, "l:", FALSE, first); } --- 6292,6299 ---- void list_func_vars(int *first) { ! if (current_funccal != NULL && current_funccal->fc_l_vars.dv_refcount > 0) ! list_hashtable_vars(¤t_funccal->fc_l_vars.dv_hashtab, "l:", FALSE, first); } *************** *** 6304,6311 **** get_current_funccal_dict(hashtab_T *ht) { if (current_funccal != NULL ! && ht == ¤t_funccal->l_vars.dv_hashtab) ! return ¤t_funccal->l_vars; return NULL; } --- 6306,6313 ---- get_current_funccal_dict(hashtab_T *ht) { if (current_funccal != NULL ! && ht == ¤t_funccal->fc_l_vars.dv_hashtab) ! return ¤t_funccal->fc_l_vars; return NULL; } *************** *** 6320,6330 **** hashitem_T *hi = NULL; char_u *varname; ! if (current_funccal == NULL || current_funccal->func->uf_scoped == NULL) return NULL; // Search in parent scope, which can be referenced from a lambda. ! current_funccal = current_funccal->func->uf_scoped; while (current_funccal != NULL) { ht = find_var_ht(name, &varname); --- 6322,6332 ---- hashitem_T *hi = NULL; char_u *varname; ! if (current_funccal == NULL || current_funccal->fc_func->uf_scoped == NULL) return NULL; // Search in parent scope, which can be referenced from a lambda. ! current_funccal = current_funccal->fc_func->uf_scoped; while (current_funccal != NULL) { ht = find_var_ht(name, &varname); *************** *** 6337,6345 **** break; } } ! if (current_funccal == current_funccal->func->uf_scoped) break; ! current_funccal = current_funccal->func->uf_scoped; } current_funccal = old_current_funccal; --- 6339,6347 ---- break; } } ! if (current_funccal == current_funccal->fc_func->uf_scoped) break; ! current_funccal = current_funccal->fc_func->uf_scoped; } current_funccal = old_current_funccal; *************** *** 6357,6367 **** hashtab_T *ht; char_u *varname; ! if (current_funccal == NULL || current_funccal->func->uf_scoped == NULL) return NULL; // Search in parent scope which is possible to reference from lambda ! current_funccal = current_funccal->func->uf_scoped; while (current_funccal) { ht = find_var_ht(name, &varname); --- 6359,6369 ---- hashtab_T *ht; char_u *varname; ! if (current_funccal == NULL || current_funccal->fc_func->uf_scoped == NULL) return NULL; // Search in parent scope which is possible to reference from lambda ! current_funccal = current_funccal->fc_func->uf_scoped; while (current_funccal) { ht = find_var_ht(name, &varname); *************** *** 6371,6379 **** if (v != NULL) break; } ! if (current_funccal == current_funccal->func->uf_scoped) break; ! current_funccal = current_funccal->func->uf_scoped; } current_funccal = old_current_funccal; --- 6373,6381 ---- if (v != NULL) break; } ! if (current_funccal == current_funccal->fc_func->uf_scoped) break; ! current_funccal = current_funccal->fc_func->uf_scoped; } current_funccal = old_current_funccal; *************** *** 6388,6399 **** { funccall_T *fc; ! for (fc = previous_funccal; fc != NULL; fc = fc->caller) { fc->fc_copyID = copyID + 1; ! if (set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1, NULL) ! || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1, NULL) ! || set_ref_in_list_items(&fc->l_varlist, copyID + 1, NULL)) return TRUE; } return FALSE; --- 6390,6401 ---- { funccall_T *fc; ! for (fc = previous_funccal; fc != NULL; fc = fc->fc_caller) { fc->fc_copyID = copyID + 1; ! if (set_ref_in_ht(&fc->fc_l_vars.dv_hashtab, copyID + 1, NULL) ! || set_ref_in_ht(&fc->fc_l_avars.dv_hashtab, copyID + 1, NULL) ! || set_ref_in_list_items(&fc->fc_l_varlist, copyID + 1, NULL)) return TRUE; } return FALSE; *************** *** 6405,6414 **** if (fc->fc_copyID != copyID) { fc->fc_copyID = copyID; ! if (set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL) ! || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL) ! || set_ref_in_list_items(&fc->l_varlist, copyID, NULL) ! || set_ref_in_func(NULL, fc->func, copyID)) return TRUE; } return FALSE; --- 6407,6416 ---- if (fc->fc_copyID != copyID) { fc->fc_copyID = copyID; ! if (set_ref_in_ht(&fc->fc_l_vars.dv_hashtab, copyID, NULL) ! || set_ref_in_ht(&fc->fc_l_avars.dv_hashtab, copyID, NULL) ! || set_ref_in_list_items(&fc->fc_l_varlist, copyID, NULL) ! || set_ref_in_func(NULL, fc->fc_func, copyID)) return TRUE; } return FALSE; *************** *** 6423,6435 **** funccall_T *fc; funccal_entry_T *entry; ! for (fc = current_funccal; fc != NULL; fc = fc->caller) if (set_ref_in_funccal(fc, copyID)) return TRUE; // Also go through the funccal_stack. for (entry = funccal_stack; entry != NULL; entry = entry->next) ! for (fc = entry->top_funccal; fc != NULL; fc = fc->caller) if (set_ref_in_funccal(fc, copyID)) return TRUE; return FALSE; --- 6425,6437 ---- funccall_T *fc; funccal_entry_T *entry; ! for (fc = current_funccal; fc != NULL; fc = fc->fc_caller) if (set_ref_in_funccal(fc, copyID)) return TRUE; // Also go through the funccal_stack. for (entry = funccal_stack; entry != NULL; entry = entry->next) ! for (fc = entry->top_funccal; fc != NULL; fc = fc->fc_caller) if (set_ref_in_funccal(fc, copyID)) return TRUE; return FALSE; *************** *** 6500,6506 **** } if (fp != NULL) { ! for (fc = fp->uf_scoped; fc != NULL; fc = fc->func->uf_scoped) abort = abort || set_ref_in_funccal(fc, copyID); } --- 6502,6508 ---- } if (fp != NULL) { ! for (fc = fp->uf_scoped; fc != NULL; fc = fc->fc_func->uf_scoped) abort = abort || set_ref_in_funccal(fc, copyID); } *** ../vim-9.0.0397/src/vim9execute.c 2022-09-06 18:31:09.070310282 +0100 --- src/vim9execute.c 2022-09-06 18:39:30.633746431 +0100 *************** *** 5080,5091 **** case ISN_PROF_END: { #ifdef FEAT_PROFILE ! funccall_T cookie; ! ufunc_T *cur_ufunc = (((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx)->df_ufunc; ! cookie.func = cur_ufunc; if (iptr->isn_type == ISN_PROF_START) { func_line_start(&cookie, iptr->isn_lnum); --- 5080,5091 ---- case ISN_PROF_END: { #ifdef FEAT_PROFILE ! funccall_T cookie; ! ufunc_T *cur_ufunc = (((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx)->df_ufunc; ! cookie.fc_func = cur_ufunc; if (iptr->isn_type == ISN_PROF_START) { func_line_start(&cookie, iptr->isn_lnum); *** ../vim-9.0.0397/src/evalvars.c 2022-09-03 10:52:18.395075356 +0100 --- src/evalvars.c 2022-09-06 18:51:55.628381740 +0100 *************** *** 3391,3397 **** if (*name == 'v') // v: variable return &vimvarht; if (get_current_funccal() != NULL ! && get_current_funccal()->func->uf_def_status == UF_NOT_COMPILED) { // a: and l: are only used in functions defined with ":function" if (*name == 'a') // a: function argument --- 3391,3398 ---- if (*name == 'v') // v: variable return &vimvarht; if (get_current_funccal() != NULL ! && get_current_funccal()->fc_func->uf_def_status ! == UF_NOT_COMPILED) { // a: and l: are only used in functions defined with ":function" if (*name == 'a') // a: function argument *** ../vim-9.0.0397/src/version.c 2022-09-06 18:31:09.074310277 +0100 --- src/version.c 2022-09-06 18:56:08.119866967 +0100 *************** *** 705,706 **** --- 705,708 ---- { /* Add new patch number below this line */ + /**/ + 398, /**/ -- hundred-and-one symptoms of being an internet addict: 18. Your wife drapes a blond wig over your monitor to remind you of what she looks like. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///